[Linux-NTFS-cvs] CVS: ntfs-driver-tng/linux/fs/ntfs upcase.c,NONE,1.1 Makefile,1.16,1.17 aops.c,1.24
Development moved to https://sourceforge.net/projects/ntfs-3g/
Brought to you by:
antona,
cha0smaster
From: Anton A. <an...@us...> - 2001-09-22 17:10:49
|
Changes by: antona Update of /cvsroot/linux-ntfs/ntfs-driver-tng/linux/fs/ntfs In directory usw-pr-cvs1:/tmp/cvs-serv12893/linux/fs/ntfs Modified Files: Makefile aops.c mft.c super.c Added Files: upcase.c Log Message: I _think_ I nailed the mount process entering D state until unrelated disk io occurs problem... --- NEW FILE --- /* * upcase.c - Generate the full NTFS Unicode upcase table in little endian. * Part of the Linux-NTFS project. * * Copyright (C) 2001 Richard Russon <nt...@fl...> * Copyright (c) 2001 Anton Altaparmakov <ai...@ca...> * * Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov. * Modified for kernel inclusion 10 September 2001 by Anton Altparmakov. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the main directory of the Linux-NTFS source * in the file COPYING); if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/ntfs_fs.h> uchar_t *generate_default_upcase(void) { const int uc_run_table[][3] = { /* Start, End, Add */ {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, {0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128}, {0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112}, {0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126}, {0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8}, {0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8}, {0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8}, {0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7}, {0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16}, {0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26}, {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, {0} }; const int uc_dup_table[][2] = { /* Start, End */ {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, {0} }; const int uc_word_table[][2] = { /* Offset, Value */ {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, {0} }; int i, r; uchar_t *uc; uc = vmalloc(default_upcase_len * sizeof(uchar_t)); if (!uc) return uc; memset(uc, 0, default_upcase_len * sizeof(uchar_t)); for (i = 0; i < default_upcase_len; i++) uc[i] = cpu_to_le16(i); for (r = 0; uc_run_table[r][0]; r++) for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) uc[i] = cpu_to_le16((le16_to_cpu(uc[i]) + uc_run_table[r][2])); for (r = 0; uc_dup_table[r][0]; r++) for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1); for (r = 0; uc_word_table[r][0]; r++) uc[uc_word_table[r][0]] = cpu_to_le16(uc_word_table[r][1]); return uc; } Index: Makefile =================================================================== RCS file: /cvsroot/linux-ntfs/ntfs-driver-tng/linux/fs/ntfs/Makefile,v retrieving revision 1.16 retrieving revision 1.17 diff -U2 -r1.16 -r1.17 --- Makefile 2001/07/31 00:11:00 1.16 +++ Makefile 2001/09/22 17:10:47 1.17 @@ -4,5 +4,5 @@ obj-y := time.o unistr.o inode.o file.o mft.o super.o debug.o aops.o \ - attrib.o dir.o namei.o mst.o + attrib.o dir.o namei.o mst.o upcase.o obj-m := $(O_TARGET) EXTRA_CFLAGS = -DNTFS_VERSION=\"TNG-0.0.1\" Index: aops.c =================================================================== RCS file: /cvsroot/linux-ntfs/ntfs-driver-tng/linux/fs/ntfs/aops.c,v retrieving revision 1.24 retrieving revision 1.25 diff -U2 -r1.24 -r1.25 --- aops.c 2001/09/21 22:06:44 1.24 +++ aops.c 2001/09/22 17:10:47 1.25 @@ -90,4 +90,5 @@ attr_search_context ctx; + // ntfs_debug("Entering for blk 0x%lx.\n", blk); /* Get hold of the run list of the unnamed data attribute. */ /* @@ -157,4 +158,5 @@ /* We do this out of line as it should only be necessary once. */ map_run_list: + ntfs_debug("(Re)Mapping run list.\n"); /* Initialize the search context. */ memset(&ctx, 0, sizeof(ctx)); @@ -214,12 +216,13 @@ static int ntfs_file_readpage(struct file *file, struct page *page) { - __s64 attr_pos; + s64 attr_pos; struct inode *vfs_ino; struct ntfs_inode_info *ntfs_ino; char *page_addr; - __u32 attr_len; + u32 attr_len; int err = 0; attr_search_context ctx; + //ntfs_debug("Entering for index 0x%lx.\n", page->index); /* The page must be locked. */ if (!PageLocked(page)) @@ -488,5 +491,5 @@ struct ntfs_inode_info *ntfs_ino; unsigned int i, recs, nr_err = 0; - __u32 rec_size; + u32 rec_size; ntfs_ino = NTFS_I(page->mapping->host); @@ -500,4 +503,5 @@ nr_err++; } + kunmap(page); if (!nr_err && recs) SetPageUptodate(page); Index: mft.c =================================================================== RCS file: /cvsroot/linux-ntfs/ntfs-driver-tng/linux/fs/ntfs/mft.c,v retrieving revision 1.19 retrieving revision 1.20 diff -U2 -r1.19 -r1.20 --- mft.c 2001/09/21 22:06:45 1.19 +++ mft.c 2001/09/22 17:10:47 1.20 @@ -140,5 +140,5 @@ struct page *page; - ntfs_debug("Executing.\n"); + //ntfs_debug("Executing.\n"); mark_buffer_uptodate(bh, uptodate); /* This is a temporary buffer used for page I/O. */ @@ -176,5 +176,5 @@ struct ntfs_sb_info *vol; unsigned int i, recs, nr_err = 0; - __u32 rec_size; + u32 rec_size; vol = NTFS_SB(page->mapping->host->i_sb); @@ -188,4 +188,5 @@ nr_err++; } + kunmap(page); if (!nr_err) SetPageUptodate(page); Index: super.c =================================================================== RCS file: /cvsroot/linux-ntfs/ntfs-driver-tng/linux/fs/ntfs/super.c,v retrieving revision 1.40 retrieving revision 1.41 diff -U2 -r1.40 -r1.41 --- super.c 2001/09/21 22:06:45 1.40 +++ super.c 2001/09/22 17:10:47 1.41 @@ -633,4 +633,120 @@ /** + * load_and_init_upcase - + * @vol: ntfs super block describing device whose upcase to load + * + * + * + * Return TRUE on success or FALSE on error. + */ +static BOOL load_and_init_upcase(struct ntfs_sb_info *vol) +{ + struct super_block *sb = vol->sb; + struct inode *ino; + struct page *page; + unsigned long index, max_index; + unsigned int size; + int i, max; + + ntfs_debug("Entering.\n"); + /* Read upcase table and setup vol->upcase and vol->upcase_len. */ + ino = iget(sb, FILE_$UpCase); + if (!ino || is_bad_inode(ino)) { + if (ino) + iput(ino); + goto upcase_failed; + } + /* + * The upcase size must not be above 64k Unicode characters, must not + * be zero and must be a multiple of sizeof(uchar_t). + */ + if (!ino->i_size || ino->i_size & (sizeof(uchar_t) - 1) || + ino->i_size > 64ULL * 1024 * sizeof(uchar_t)) + goto iput_upcase_failed; + vol->upcase = (uchar_t*)vmalloc_nofs(ino->i_size); + if (!vol->upcase) + goto iput_upcase_failed; + index = 0; + max_index = ino->i_size >> PAGE_CACHE_SHIFT; + size = PAGE_CACHE_SIZE; + while (index < max_index) { +read_partial_upcase_page: + /* + * Read the page from page cache, getting it from backing store + * if necessary, and increment the use count. + */ + page = read_cache_page(ino->i_mapping, index, (filler_t*) + ino->i_mapping->a_ops->readpage, NULL); + if (IS_ERR(page)) + /* Sync io failed. */ + goto iput_upcase_failed; + wait_on_page(page); + if (!Page_Uptodate(page)) { + /* Async io failed. */ + page_cache_release(page); + goto iput_upcase_failed; + } + memcpy((char*)vol->upcase + (index++ << PAGE_CACHE_SHIFT), + kmap(page), size); + kunmap(page); + page_cache_release(page); + }; + if (size == PAGE_CACHE_SIZE) { + size = ino->i_size & ~PAGE_CACHE_MASK; + if (size) + goto read_partial_upcase_page; + } + vol->upcase_len = ino->i_size >> 1 /* uchar_t_size_shift */; + ntfs_debug("Read %Lu bytes from $UpCase (expected %u bytes).\n", + ino->i_size, 64 * 1024 * sizeof(uchar_t)); + iput(ino); + down(&ntfs_lock); + if (!default_upcase) { + ntfs_debug("Using volume specified $UpCase since default is " + "not present.\n"); + up(&ntfs_lock); + return TRUE; + } + max = default_upcase_len; + if (vol->upcase_len < default_upcase_len) + max = vol->upcase_len; + for (i = 0; i < max; i++) + if (vol->upcase[i] != default_upcase[i]) + break; + if (i == max) { + vfree(vol->upcase); + vol->upcase = default_upcase; + vol->upcase_len = max; + ntfs_nr_upcase_users++; + up(&ntfs_lock); + ntfs_debug("Volume specified $UpCase matches default. Using " + "default.\n"); + return TRUE; + } + up(&ntfs_lock); + ntfs_debug("Using volume specified $UpCase since it does not match " + "the default.\n"); + return TRUE; +iput_upcase_failed: + iput(ino); + vfree(vol->upcase); + vol->upcase = NULL; +upcase_failed: + down(&ntfs_lock); + if (default_upcase) { + vol->upcase = default_upcase; + vol->upcase_len = default_upcase_len; + ntfs_nr_upcase_users++; + up(&ntfs_lock); + ntfs_error(sb, __FUNCTION__ "(): Failed to load $UpCase from " + "the volume. Using default."); + return TRUE; + } + up(&ntfs_lock); + ntfs_error(sb, __FUNCTION__ "(): Failed to initialized upcase table."); + return FALSE; +} + +/** * load_system_files - open the system files using normal functions * @vol: ntfs super block describing device whose system files to load @@ -645,12 +761,10 @@ struct super_block *sb = vol->sb; struct inode *tmp_ino; - struct page *page; MFT_RECORD *m; VOLUME_INFORMATION *vi; - unsigned long index, max_index; - unsigned int size; attr_search_context ctx; run_list *rl; + ntfs_debug("Entering.\n"); /* * We have $MFT already (vol->mft_ino) but we need to setup access to @@ -730,63 +844,8 @@ // FIXME: Compare mftmirr with mft and repair if appropriate and not // a read-only mount. + /* Read upcase table and setup vol->upcase and vol->upcase_len. */ - tmp_ino = iget(sb, FILE_$UpCase); - if (!tmp_ino || is_bad_inode(tmp_ino)) { - if (is_bad_inode(tmp_ino)) - iput(tmp_ino); - goto upcase_failed; - } - /* - * The upcase size must not be above 64k Unicode characters, must not - * be zero and must be a multiple of sizeof(uchar_t). - */ - if (!tmp_ino->i_size || tmp_ino->i_size & (sizeof(uchar_t) - 1) || - tmp_ino->i_size > 64ULL * 1024 * sizeof(uchar_t)) { -iput_upcase_failed: - iput(tmp_ino); - vfree(vol->upcase); - vol->upcase = NULL; -upcase_failed: - ntfs_error(sb, __FUNCTION__ "(): Failed to load $UpCase."); - // FIXME: Can generate default and use that instead of failing. + if (load_and_init_upcase(vol) == FALSE) goto iput_mirr_err_out; - } - vol->upcase = (uchar_t*)vmalloc_nofs(tmp_ino->i_size); - if (!vol->upcase) - goto iput_upcase_failed; - index = 0; - max_index = tmp_ino->i_size >> PAGE_CACHE_SHIFT; - size = PAGE_CACHE_SIZE; - while (index < max_index) { -read_partial_upcase_page: - /* - * Read the page from page cache, getting it from backing store - * if necessary, and increment the use count. - */ - page = read_cache_page(tmp_ino->i_mapping, index, (filler_t*) - tmp_ino->i_mapping->a_ops->readpage, NULL); - if (IS_ERR(page)) - /* Sync io failed. */ - goto iput_upcase_failed; - wait_on_page(page); - if (!Page_Uptodate(page)) { - /* Async io failed. */ - page_cache_release(page); - goto iput_upcase_failed; - } - memcpy((char*)vol->upcase + (index++ << PAGE_CACHE_SHIFT), - kmap(page), size); - kunmap(page); - page_cache_release(page); - }; - if (size == PAGE_CACHE_SIZE) { - size = tmp_ino->i_size & ~PAGE_CACHE_MASK; - if (size) - goto read_partial_upcase_page; - } - vol->upcase_len = tmp_ino->i_size >> 1 /* uchar_t_size_shift */; - ntfs_debug("Read %Lu bytes from $UpCase (expected %u bytes).\n", - tmp_ino->i_size, 64 * 1024 * sizeof(uchar_t)); - iput(tmp_ino); /* Get the cluster allocation bitmap inode and verify the size. */ down_write(&vol->lcnbmp_lock); @@ -958,5 +1017,4 @@ iput(vol->mft_ino); vol->mft_ino = NULL; - vol->upcase_len = 0; down_write(&vol->mftbmp_lock); /* @@ -970,6 +1028,25 @@ vol->mftbmp_rl = NULL; up_write(&vol->mftbmp_lock); - vfree(vol->upcase); - vol->upcase = NULL; + vol->upcase_len = 0; + /* + * Decrease the number of mounts and destroy the global default upcase + * table if necessary. Also decrease the number of upcase users if we + * are were user. + */ + down(&ntfs_lock); + ntfs_nr_mounts--; + if (vol->upcase == default_upcase) { + ntfs_nr_upcase_users--; + vol->upcase = NULL; + } + if (!ntfs_nr_upcase_users && default_upcase) { + vfree(default_upcase); + default_upcase = NULL; + } + up(&ntfs_lock); + if (vol->upcase) { + vfree(vol->upcase); + vol->upcase = NULL; + } if (vol->nls_map) { unload_nls(vol->nls_map); @@ -988,5 +1065,5 @@ * found. This means we return an underestimate on error. */ -__s64 get_nr_free_clusters(struct ntfs_sb_info *vol) +s64 get_nr_free_clusters(struct ntfs_sb_info *vol) { struct address_space *mapping = vol->lcnbmp_ino->i_mapping; @@ -1069,5 +1146,5 @@ * found. This means we return an underestimate on error. */ -__s64 get_nr_free_mft_records(struct ntfs_sb_info *vol) +s64 get_nr_free_mft_records(struct ntfs_sb_info *vol) { struct address_space *mapping; @@ -1437,4 +1514,14 @@ */ /* + * Increment the number of mounts and generate the global default + * upcase table if necessary. Also temporarily increment the number of + * upcase users to avoid race conditions with concurrent (u)mounts. + */ + down(&ntfs_lock); + if (!ntfs_nr_mounts++) + default_upcase = generate_default_upcase(); + ntfs_nr_upcase_users++; + up(&ntfs_lock); + /* * From now on, ignore @silent parameter. If we fail below this line, * it will be due to a corrupt fs or a system error, so we report it. @@ -1446,5 +1533,5 @@ if (!load_system_files(vol)) { ntfs_error(sb, __FUNCTION__ "(): Failed to load system files."); - goto iput_tmp_ino_err_out_now; + goto unl_upcase_iput_tmp_ino_err_out_now; } @@ -1453,4 +1540,11 @@ atomic_inc(&vol->root_ino->i_count); ntfs_debug("Exiting, status successful.\n"); + /* Release the default upcase if it has no users. */ + down(&ntfs_lock); + if (!--ntfs_nr_upcase_users && default_upcase) { + vfree(default_upcase); + default_upcase = NULL; + } + up(&ntfs_lock); return sb; } @@ -1470,8 +1564,9 @@ iput(vol->mftmirr_ino); vol->mftmirr_ino = NULL; - vol->upcase_len = 0; vfree(vol->mftbmp_rl); vol->mftbmp_rl = NULL; - vfree(vol->upcase); + vol->upcase_len = 0; + if (vol->upcase != default_upcase) + vfree(vol->upcase); vol->upcase = NULL; if (vol->nls_map) { @@ -1480,4 +1575,16 @@ } /* Error exit code path. */ +unl_upcase_iput_tmp_ino_err_out_now: + /* + * Decrease the number of mounts and destroy the global default upcase + * table if necessary. + */ + down(&ntfs_lock); + ntfs_nr_mounts--; + if (!--ntfs_nr_upcase_users && default_upcase) { + vfree(default_upcase); + default_upcase = NULL; + } + up(&ntfs_lock); iput_tmp_ino_err_out_now: iput(tmp_ino); @@ -1518,10 +1625,32 @@ kmem_cache_t *ntfs_name_cache; +/* A global default upcase table. */ +wchar_t *default_upcase = NULL; +/* The number of users of the default_upcase table. */ +unsigned long ntfs_nr_upcase_users = 0; + +/* The number of mounted filesystems. */ +unsigned long ntfs_nr_mounts = 0; + +/* Driver wide semaphore. */ +DECLARE_MUTEX(ntfs_lock); + static DECLARE_FSTYPE_DEV(ntfs_fs_type, "ntfs", ntfs_read_super); static int __init init_ntfs_fs(void) { - printk(KERN_INFO "NTFS driver " NTFS_VERSION ". " - "Copyright (c) 2001 Anton Altaparmakov.\n"); + printk(KERN_INFO "NTFS driver " NTFS_VERSION " [Flags: R/" +#ifdef CONFIG_NTFS_RW + "W" +#else + "O" +#endif +#ifdef DEBUG + " DEBUG" +#endif +#ifdef MODULE + " MODULE" +#endif + "]. Copyright (c) 2001 Anton Altaparmakov.\n"); ntfs_name_cache = kmem_cache_create("ntfs_name_cache", (NTFS_MAX_NAME_LEN+1) * sizeof(uchar_t), 0 /* offset */, |