X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fntfs%2Fsuper.c;h=212a3d0f207317f9aa07ec9d45bc770de396c19f;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=e49428592e0403535fb46ff47c8354003e019313;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index e49428592..212a3d0f2 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -28,17 +28,26 @@ #include #include #include +#include +#include -#include "ntfs.h" #include "sysctl.h" #include "logfile.h" #include "quota.h" #include "dir.h" +#include "debug.h" #include "index.h" +#include "aops.h" +#include "malloc.h" +#include "ntfs.h" /* Number of mounted file systems which have compression enabled. */ static unsigned long ntfs_nr_compression_users; +/* A global default upcase table and a corresponding reference count. */ +static ntfschar *default_upcase = NULL; +static unsigned long ntfs_nr_upcase_users = 0; + /* Error constants/strings used in inode.c::ntfs_show_options(). */ typedef enum { /* One of these must be present, default is ON_ERRORS_CONTINUE. */ @@ -143,7 +152,7 @@ static BOOL parse_options(ntfs_volume *vol, char *opt) ntfs_debug("Entering with mount options string: %s", opt); while ((p = strsep(&opt, ","))) { if ((v = strchr(p, '='))) - *v++ = '\0'; + *v++ = 0; NTFS_GETOPT("uid", uid) else NTFS_GETOPT("gid", gid) else NTFS_GETOPT("umask", fmask = dmask) @@ -316,11 +325,11 @@ static int ntfs_write_volume_flags(ntfs_volume *vol, const VOLUME_FLAGS flags) ntfs_inode *ni = NTFS_I(vol->vol_ino); MFT_RECORD *m; VOLUME_INFORMATION *vi; - attr_search_context *ctx; + ntfs_attr_search_ctx *ctx; int err; ntfs_debug("Entering, old flags = 0x%x, new flags = 0x%x.", - vol->vol_flags, flags); + le16_to_cpu(vol->vol_flags), le16_to_cpu(flags)); if (vol->vol_flags == flags) goto done; BUG_ON(!ni); @@ -329,28 +338,28 @@ static int ntfs_write_volume_flags(ntfs_volume *vol, const VOLUME_FLAGS flags) err = PTR_ERR(m); goto err_out; } - ctx = get_attr_search_ctx(ni, m); + ctx = ntfs_attr_get_search_ctx(ni, m); if (!ctx) { err = -ENOMEM; goto put_unm_err_out; } - if (!lookup_attr(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx)) { - err = -EIO; + err = ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, + ctx); + if (err) goto put_unm_err_out; - } vi = (VOLUME_INFORMATION*)((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset)); vol->vol_flags = vi->flags = flags; flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); - put_attr_search_ctx(ctx); + ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni); done: ntfs_debug("Done."); return 0; put_unm_err_out: if (ctx) - put_attr_search_ctx(ctx); + ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni); err_out: ntfs_error(vol->sb, "Failed with error code %i.", -err); @@ -384,7 +393,8 @@ static inline int ntfs_set_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags) static inline int ntfs_clear_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags) { flags &= VOLUME_FLAGS_MASK; - return ntfs_write_volume_flags(vol, vol->vol_flags & ~flags); + flags = vol->vol_flags & cpu_to_le16(~le16_to_cpu(flags)); + return ntfs_write_volume_flags(vol, flags); } #endif /* NTFS_RW */ @@ -409,7 +419,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) #ifndef NTFS_RW /* For read-only compiled driver, enforce all read-only flags. */ *flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; -#else /* ! NTFS_RW */ +#else /* NTFS_RW */ /* * For the read-write compiled driver, if we are remounting read-write, * make sure there are no volume errors and that no unsupported volume @@ -479,28 +489,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) "flags. Run chkdsk."); } } - // TODO: For now we enforce no atime and dir atime updates as they are - // not implemented. - if ((sb->s_flags & MS_NOATIME) && !(*flags & MS_NOATIME)) - ntfs_warning(sb, "Atime updates are not implemented yet. " - "Leaving them disabled."); - else if ((sb->s_flags & MS_NODIRATIME) && !(*flags & MS_NODIRATIME)) - ntfs_warning(sb, "Directory atime updates are not implemented " - "yet. Leaving them disabled."); - *flags |= MS_NOATIME | MS_NODIRATIME; -#endif /* ! NTFS_RW */ - - // FIXME/TODO: If left like this we will have problems with rw->ro and - // ro->rw, as well as with sync->async and vice versa remounts. - // Note: The VFS already checks that there are no pending deletes and - // no open files for writing. So we only need to worry about dirty - // inode pages and dirty system files (which include dirty inodes). - // Either handle by flushing the whole volume NOW or by having the - // write routines work on MS_RDONLY fs and guarantee we don't mark - // anything as dirty if MS_RDONLY is set. That way the dirty data - // would get flushed but no new dirty data would appear. This is - // probably best but we need to be careful not to mark anything dirty - // or the MS_RDONLY will be leaking writes. +#endif /* NTFS_RW */ // TODO: Deal with *flags. @@ -530,8 +519,10 @@ static BOOL is_boot_sector_ntfs(const struct super_block *sb, * field. If checksum is zero, no checking is done. */ if ((void*)b < (void*)&b->checksum && b->checksum) { - u32 i, *u; - for (i = 0, u = (u32*)b; u < (u32*)(&b->checksum); ++u) + le32 *u; + u32 i; + + for (i = 0, u = (le32*)b; u < (le32*)(&b->checksum); ++u) i += le32_to_cpup(u); if (le32_to_cpu(b->checksum) != i) goto not_ntfs; @@ -540,7 +531,7 @@ static BOOL is_boot_sector_ntfs(const struct super_block *sb, if (b->oem_id != magicNTFS) goto not_ntfs; /* Check bytes per sector value is between 256 and 4096. */ - if (le16_to_cpu(b->bpb.bytes_per_sector) < 0x100 || + if (le16_to_cpu(b->bpb.bytes_per_sector) < 0x100 || le16_to_cpu(b->bpb.bytes_per_sector) > 0x1000) goto not_ntfs; /* Check sectors per cluster value is valid. */ @@ -693,7 +684,7 @@ hotfix_primary_boot_sector: * @b: boot sector to parse * * Parse the ntfs boot sector @b and store all imporant information therein in - * the ntfs super block @vol. Return TRUE on success and FALSE on error. + * the ntfs super block @vol. Return TRUE on success and FALSE on error. */ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) { @@ -726,12 +717,12 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) vol->cluster_size_bits, vol->cluster_size_bits); if (vol->sector_size > vol->cluster_size) { ntfs_error(vol->sb, "Sector sizes above the cluster size are " - "not supported. Sorry."); + "not supported. Sorry."); return FALSE; } if (vol->sb->s_blocksize > vol->cluster_size) { ntfs_error(vol->sb, "Cluster sizes smaller than the device " - "sector size are not supported. Sorry."); + "sector size are not supported. Sorry."); return FALSE; } clusters_per_mft_record = b->clusters_per_mft_record; @@ -755,6 +746,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) vol->mft_record_size_mask); ntfs_debug("vol->mft_record_size_bits = %i (0x%x)", vol->mft_record_size_bits, vol->mft_record_size_bits); + /* + * We cannot support mft record sizes above the PAGE_CACHE_SIZE since + * we store $MFT/$DATA, the table of mft records in the page cache. + */ + if (vol->mft_record_size > PAGE_CACHE_SIZE) { + ntfs_error(vol->sb, "Mft record size %i (0x%x) exceeds the " + "page cache size on your system %lu (0x%lx). " + "This is not supported. Sorry.", + vol->mft_record_size, vol->mft_record_size, + PAGE_CACHE_SIZE, PAGE_CACHE_SIZE); + return FALSE; + } clusters_per_index_record = b->clusters_per_index_record; ntfs_debug("clusters_per_index_record = %i (0x%x)", clusters_per_index_record, clusters_per_index_record); @@ -785,7 +788,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) */ ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits; if ((u64)ll >= 1ULL << 32) { - ntfs_error(vol->sb, "Cannot handle 64-bit clusters. Sorry."); + ntfs_error(vol->sb, "Cannot handle 64-bit clusters. Sorry."); return FALSE; } vol->nr_clusters = ll; @@ -798,8 +801,8 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) if (sizeof(unsigned long) < 8) { if ((ll << vol->cluster_size_bits) >= (1ULL << 41)) { ntfs_error(vol->sb, "Volume size (%lluTiB) is too " - "large for this architecture. Maximum " - "supported is 2TiB. Sorry.", + "large for this architecture. " + "Maximum supported is 2TiB. Sorry.", (unsigned long long)ll >> (40 - vol->cluster_size_bits)); return FALSE; @@ -807,14 +810,14 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) } ll = sle64_to_cpu(b->mft_lcn); if (ll >= vol->nr_clusters) { - ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird."); + ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird."); return FALSE; } vol->mft_lcn = ll; ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn); ll = sle64_to_cpu(b->mftmirr_lcn); if (ll >= vol->nr_clusters) { - ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. " + ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. " "Weird."); return FALSE; } @@ -839,37 +842,91 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) vol->serial_no = le64_to_cpu(b->volume_serial_number); ntfs_debug("vol->serial_no = 0x%llx", (unsigned long long)vol->serial_no); - /* - * Determine MFT zone size. This is not strictly the right place to do - * this, but I am too lazy to create a function especially for it... - */ - vol->mft_zone_end = vol->nr_clusters; + return TRUE; +} + +/** + * ntfs_setup_allocators - initialize the cluster and mft allocators + * @vol: volume structure for which to setup the allocators + * + * Setup the cluster (lcn) and mft allocators to the starting values. + */ +static void ntfs_setup_allocators(ntfs_volume *vol) +{ +#ifdef NTFS_RW + LCN mft_zone_size, mft_lcn; +#endif /* NTFS_RW */ + + ntfs_debug("vol->mft_zone_multiplier = 0x%x", + vol->mft_zone_multiplier); +#ifdef NTFS_RW + /* Determine the size of the MFT zone. */ + mft_zone_size = vol->nr_clusters; switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */ case 4: - vol->mft_zone_end = vol->mft_zone_end >> 1; /* 50% */ + mft_zone_size >>= 1; /* 50% */ break; case 3: - vol->mft_zone_end = (vol->mft_zone_end + - (vol->mft_zone_end >> 1)) >> 2; /* 37.5% */ + mft_zone_size = (mft_zone_size + + (mft_zone_size >> 1)) >> 2; /* 37.5% */ break; case 2: - vol->mft_zone_end = vol->mft_zone_end >> 2; /* 25% */ + mft_zone_size >>= 2; /* 25% */ break; + /* case 1: */ default: - vol->mft_zone_multiplier = 1; - /* Fall through into case 1. */ - case 1: - vol->mft_zone_end = vol->mft_zone_end >> 3; /* 12.5% */ + mft_zone_size >>= 3; /* 12.5% */ break; } - ntfs_debug("vol->mft_zone_multiplier = 0x%x", - vol->mft_zone_multiplier); - vol->mft_zone_start = vol->mft_lcn; - vol->mft_zone_end += vol->mft_lcn; + /* Setup the mft zone. */ + vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn; + ntfs_debug("vol->mft_zone_pos = 0x%llx", + (unsigned long long)vol->mft_zone_pos); + /* + * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs + * source) and if the actual mft_lcn is in the expected place or even + * further to the front of the volume, extend the mft_zone to cover the + * beginning of the volume as well. This is in order to protect the + * area reserved for the mft bitmap as well within the mft_zone itself. + * On non-standard volumes we do not protect it as the overhead would + * be higher than the speed increase we would get by doing it. + */ + mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size; + if (mft_lcn * vol->cluster_size < 16 * 1024) + mft_lcn = (16 * 1024 + vol->cluster_size - 1) / + vol->cluster_size; + if (vol->mft_zone_start <= mft_lcn) + vol->mft_zone_start = 0; ntfs_debug("vol->mft_zone_start = 0x%llx", - (long long)vol->mft_zone_start); - ntfs_debug("vol->mft_zone_end = 0x%llx", (long long)vol->mft_zone_end); - return TRUE; + (unsigned long long)vol->mft_zone_start); + /* + * Need to cap the mft zone on non-standard volumes so that it does + * not point outside the boundaries of the volume. We do this by + * halving the zone size until we are inside the volume. + */ + vol->mft_zone_end = vol->mft_lcn + mft_zone_size; + while (vol->mft_zone_end >= vol->nr_clusters) { + mft_zone_size >>= 1; + vol->mft_zone_end = vol->mft_lcn + mft_zone_size; + } + ntfs_debug("vol->mft_zone_end = 0x%llx", + (unsigned long long)vol->mft_zone_end); + /* + * Set the current position within each data zone to the start of the + * respective zone. + */ + vol->data1_zone_pos = vol->mft_zone_end; + ntfs_debug("vol->data1_zone_pos = 0x%llx", + (unsigned long long)vol->data1_zone_pos); + vol->data2_zone_pos = 0; + ntfs_debug("vol->data2_zone_pos = 0x%llx", + (unsigned long long)vol->data2_zone_pos); + + /* Set the mft data allocation position to mft record 24. */ + vol->mft_data_pos = 24; + ntfs_debug("vol->mft_data_pos = 0x%llx", + (unsigned long long)vol->mft_data_pos); +#endif /* NTFS_RW */ } #ifdef NTFS_RW @@ -905,8 +962,8 @@ static BOOL load_and_init_mft_mirror(ntfs_volume *vol) /* No VFS initiated operations allowed for $MFTMirr. */ tmp_ino->i_op = &ntfs_empty_inode_ops; tmp_ino->i_fop = &ntfs_empty_file_ops; - /* Put back our special address space operations. */ - tmp_ino->i_mapping->a_ops = &ntfs_mft_aops; + /* Put in our special address space operations. */ + tmp_ino->i_mapping->a_ops = &ntfs_mst_aops; tmp_ni = NTFS_I(tmp_ino); /* The $MFTMirr, like the $MFT is multi sector transfer protected. */ NInoSetMstProtected(tmp_ni); @@ -926,6 +983,10 @@ static BOOL load_and_init_mft_mirror(ntfs_volume *vol) * @vol: ntfs super block describing device whose mft mirror to check * * Return TRUE on success or FALSE on error. + * + * Note, this function also results in the mft mirror runlist being completely + * mapped into memory. The mft mirror write code requires this and will BUG() + * should it find an unmapped runlist element. */ static BOOL check_mft_mirror(ntfs_volume *vol) { @@ -934,7 +995,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol) ntfs_inode *mirr_ni; struct page *mft_page, *mirr_page; u8 *kmft, *kmirr; - run_list_element *rl, rl2[2]; + runlist_element *rl, rl2[2]; int mrecs_per_page, i; ntfs_debug("Entering."); @@ -973,7 +1034,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol) ++index; } /* Make sure the record is ok. */ - if (ntfs_is_baad_recordp(kmft)) { + if (ntfs_is_baad_recordp((le32*)kmft)) { ntfs_error(sb, "Incomplete multi sector transfer " "detected in mft record %i.", i); mm_unmap_out: @@ -982,7 +1043,7 @@ mft_unmap_out: ntfs_unmap_page(mft_page); return FALSE; } - if (ntfs_is_baad_recordp(kmirr)) { + if (ntfs_is_baad_recordp((le32*)kmirr)) { ntfs_error(sb, "Incomplete multi sector transfer " "detected in mft mirror record %i.", i); goto mm_unmap_out; @@ -1007,7 +1068,7 @@ mft_unmap_out: ntfs_unmap_page(mft_page); ntfs_unmap_page(mirr_page); - /* Construct the mft mirror run list by hand. */ + /* Construct the mft mirror runlist by hand. */ rl2[0].vcn = 0; rl2[0].lcn = vol->mftmirr_lcn; rl2[0].length = (vol->mftmirr_size * vol->mft_record_size + @@ -1017,23 +1078,23 @@ mft_unmap_out: rl2[1].length = 0; /* * Because we have just read all of the mft mirror, we know we have - * mapped the full run list for it. + * mapped the full runlist for it. */ mirr_ni = NTFS_I(vol->mftmirr_ino); - down_read(&mirr_ni->run_list.lock); - rl = mirr_ni->run_list.rl; - /* Compare the two run lists. They must be identical. */ + down_read(&mirr_ni->runlist.lock); + rl = mirr_ni->runlist.rl; + /* Compare the two runlists. They must be identical. */ i = 0; do { if (rl2[i].vcn != rl[i].vcn || rl2[i].lcn != rl[i].lcn || rl2[i].length != rl[i].length) { ntfs_error(sb, "$MFTMirr location mismatch. " "Run chkdsk."); - up_read(&mirr_ni->run_list.lock); + up_read(&mirr_ni->runlist.lock); return FALSE; } } while (rl2[i++].length); - up_read(&mirr_ni->run_list.lock); + up_read(&mirr_ni->runlist.lock); ntfs_debug("Done."); return TRUE; } @@ -1081,9 +1142,9 @@ static BOOL load_and_init_quota(ntfs_volume *vol) static const ntfschar Quota[7] = { const_cpu_to_le16('$'), const_cpu_to_le16('Q'), const_cpu_to_le16('u'), const_cpu_to_le16('o'), const_cpu_to_le16('t'), - const_cpu_to_le16('a'), const_cpu_to_le16(0) }; + const_cpu_to_le16('a'), 0 }; static ntfschar Q[3] = { const_cpu_to_le16('$'), - const_cpu_to_le16('Q'), const_cpu_to_le16(0) }; + const_cpu_to_le16('Q'), 0 }; ntfs_debug("Entering."); /* @@ -1136,6 +1197,66 @@ static BOOL load_and_init_quota(ntfs_volume *vol) return TRUE; } +/** + * load_and_init_attrdef - load the attribute definitions table for a volume + * @vol: ntfs super block describing device whose attrdef to load + * + * Return TRUE on success or FALSE on error. + */ +static BOOL load_and_init_attrdef(ntfs_volume *vol) +{ + struct super_block *sb = vol->sb; + struct inode *ino; + struct page *page; + unsigned long index, max_index; + unsigned int size; + + ntfs_debug("Entering."); + /* Read attrdef table and setup vol->attrdef and vol->attrdef_size. */ + ino = ntfs_iget(sb, FILE_AttrDef); + if (IS_ERR(ino) || is_bad_inode(ino)) { + if (!IS_ERR(ino)) + iput(ino); + goto failed; + } + /* The size of FILE_AttrDef must be above 0 and fit inside 31 bits. */ + if (!ino->i_size || ino->i_size > 0x7fffffff) + goto iput_failed; + vol->attrdef = (ATTR_DEF*)ntfs_malloc_nofs(ino->i_size); + if (!vol->attrdef) + goto iput_failed; + index = 0; + max_index = ino->i_size >> PAGE_CACHE_SHIFT; + size = PAGE_CACHE_SIZE; + while (index < max_index) { + /* Read the attrdef table and copy it into the linear buffer. */ +read_partial_attrdef_page: + page = ntfs_map_page(ino->i_mapping, index); + if (IS_ERR(page)) + goto free_iput_failed; + memcpy((u8*)vol->attrdef + (index++ << PAGE_CACHE_SHIFT), + page_address(page), size); + ntfs_unmap_page(page); + }; + if (size == PAGE_CACHE_SIZE) { + size = ino->i_size & ~PAGE_CACHE_MASK; + if (size) + goto read_partial_attrdef_page; + } + vol->attrdef_size = ino->i_size; + ntfs_debug("Read %llu bytes from $AttrDef.", ino->i_size); + iput(ino); + return TRUE; +free_iput_failed: + ntfs_free(vol->attrdef); + vol->attrdef = NULL; +iput_failed: + iput(ino); +failed: + ntfs_error(sb, "Failed to initialize attribute definition table."); + return FALSE; +} + #endif /* NTFS_RW */ /** @@ -1236,7 +1357,7 @@ upcase_failed: return TRUE; } up(&ntfs_lock); - ntfs_error(sb, "Failed to initialized upcase table."); + ntfs_error(sb, "Failed to initialize upcase table."); return FALSE; } @@ -1252,10 +1373,9 @@ upcase_failed: static BOOL load_system_files(ntfs_volume *vol) { struct super_block *sb = vol->sb; - struct inode *tmp_ino; MFT_RECORD *m; VOLUME_INFORMATION *vi; - attr_search_context *ctx; + ntfs_attr_search_ctx *ctx; ntfs_debug("Entering."); #ifdef NTFS_RW @@ -1296,6 +1416,14 @@ static BOOL load_system_files(ntfs_volume *vol) /* Read upcase table and setup @vol->upcase and @vol->upcase_len. */ if (!load_and_init_upcase(vol)) goto iput_mftbmp_err_out; +#ifdef NTFS_RW + /* + * Read attribute definitions table and setup @vol->attrdef and + * @vol->attrdef_size. + */ + if (!load_and_init_attrdef(vol)) + goto iput_upcase_err_out; +#endif /* NTFS_RW */ /* * Get the cluster allocation bitmap inode and verify the size, no * need for any locking at this stage as we are already running @@ -1311,7 +1439,7 @@ static BOOL load_system_files(ntfs_volume *vol) iput(vol->lcnbmp_ino); bitmap_failed: ntfs_error(sb, "Failed to load $Bitmap."); - goto iput_mirr_err_out; + goto iput_attrdef_err_out; } /* * Get the volume inode and setup our cache of the volume flags and @@ -1331,14 +1459,14 @@ iput_volume_failed: iput(vol->vol_ino); goto volume_failed; } - if (!(ctx = get_attr_search_ctx(NTFS_I(vol->vol_ino), m))) { + if (!(ctx = ntfs_attr_get_search_ctx(NTFS_I(vol->vol_ino), m))) { ntfs_error(sb, "Failed to get attribute search context."); goto get_ctx_vol_failed; } - if (!lookup_attr(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx) || - ctx->attr->non_resident || ctx->attr->flags) { + if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, + ctx) || ctx->attr->non_resident || ctx->attr->flags) { err_put_vol: - put_attr_search_ctx(ctx); + ntfs_attr_put_search_ctx(ctx); get_ctx_vol_failed: unmap_mft_record(NTFS_I(vol->vol_ino)); goto iput_volume_failed; @@ -1354,7 +1482,7 @@ get_ctx_vol_failed: vol->vol_flags = vi->flags; vol->major_ver = vi->major_ver; vol->minor_ver = vi->minor_ver; - put_attr_search_ctx(ctx); + ntfs_attr_put_search_ctx(ctx); unmap_mft_record(NTFS_I(vol->vol_ino)); printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver, vol->minor_ver); @@ -1483,19 +1611,6 @@ get_ctx_vol_failed: NVolSetErrors(vol); } #endif /* NTFS_RW */ - /* - * Get the inode for the attribute definitions file and parse the - * attribute definitions. - */ - tmp_ino = ntfs_iget(sb, FILE_AttrDef); - if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) { - if (!IS_ERR(tmp_ino)) - iput(tmp_ino); - ntfs_error(sb, "Failed to load $AttrDef."); - goto iput_logfile_err_out; - } - // FIXME: Parse the attribute definitions. - iput(tmp_ino); /* Get the root directory inode. */ vol->root_ino = ntfs_iget(sb, FILE_root); if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) { @@ -1591,6 +1706,26 @@ iput_vol_err_out: iput(vol->vol_ino); iput_lcnbmp_err_out: iput(vol->lcnbmp_ino); +iput_attrdef_err_out: + vol->attrdef_size = 0; + if (vol->attrdef) { + ntfs_free(vol->attrdef); + vol->attrdef = NULL; + } +#ifdef NTFS_RW +iput_upcase_err_out: +#endif /* NTFS_RW */ + vol->upcase_len = 0; + down(&ntfs_lock); + if (vol->upcase == default_upcase) { + ntfs_nr_upcase_users--; + vol->upcase = NULL; + } + up(&ntfs_lock); + if (vol->upcase) { + ntfs_free(vol->upcase); + vol->upcase = NULL; + } iput_mftbmp_err_out: iput(vol->mftbmp_ino); iput_mirr_err_out: @@ -1762,14 +1897,18 @@ static void ntfs_put_super(struct super_block *sb) iput(vol->mft_ino); vol->mft_ino = NULL; + /* Throw away the table of attribute definitions. */ + vol->attrdef_size = 0; + if (vol->attrdef) { + ntfs_free(vol->attrdef); + vol->attrdef = 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 a user. + * Destroy the global default upcase table if necessary. Also decrease + * the number of upcase users if we are a user. */ down(&ntfs_lock); - ntfs_nr_mounts--; if (vol->upcase == default_upcase) { ntfs_nr_upcase_users--; vol->upcase = NULL; @@ -1906,7 +2045,7 @@ static s64 get_nr_free_clusters(ntfs_volume *vol) */ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol) { - s64 nr_free = vol->nr_mft_records; + s64 nr_free; u32 *kaddr; struct address_space *mapping = vol->mftbmp_ino->i_mapping; filler_t *readpage = (filler_t*)mapping->a_ops->readpage; @@ -1915,13 +2054,16 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol) unsigned int max_size; ntfs_debug("Entering."); + /* Number of mft records in file system (at this point in time). */ + nr_free = vol->mft_ino->i_size >> vol->mft_record_size_bits; /* - * Convert the number of bits into bytes rounded up, then convert into - * multiples of PAGE_CACHE_SIZE, rounding up so that if we have one - * full and one partial page max_index = 2. + * Convert the maximum number of set bits into bytes rounded up, then + * convert into multiples of PAGE_CACHE_SIZE, rounding up so that if we + * have one full and one partial page max_index = 2. */ - max_index = (((vol->nr_mft_records + 7) >> 3) + PAGE_CACHE_SIZE - 1) >> - PAGE_CACHE_SHIFT; + max_index = ((((NTFS_I(vol->mft_ino)->initialized_size >> + vol->mft_record_size_bits) + 7) >> 3) + + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; /* Use multiples of 4 bytes. */ max_size = PAGE_CACHE_SIZE >> 2; ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = " @@ -2016,9 +2158,9 @@ static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs) sfs->f_bavail = sfs->f_bfree = size; /* Serialize accesses to the inode bitmap. */ down_read(&vol->mftbmp_lock); - /* Total file nodes in file system (at this moment in time). */ - sfs->f_files = vol->mft_ino->i_size >> vol->mft_record_size_bits; - /* Free file nodes in fs (based on current total count). */ + /* Number of inodes in file system (at this point in time). */ + sfs->f_files = vol->mft_ino->i_size >> vol->mft_record_size_bits; + /* Free inodes in fs (based on current total count). */ sfs->f_ffree = __get_nr_free_mft_records(vol); up_read(&vol->mftbmp_lock); /* @@ -2041,7 +2183,7 @@ static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs) /** * The complete super operations. */ -struct super_operations ntfs_sops = { +static struct super_operations ntfs_sops = { .alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */ .destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */ .put_inode = ntfs_put_inode, /* VFS: Called just before @@ -2139,15 +2281,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ntfs_debug("Entering."); #ifndef NTFS_RW sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; -#else - if (!(sb->s_flags & MS_NOATIME)) - ntfs_warning(sb, "Atime updates are not implemented yet. " - "Disabling them."); - else if (!(sb->s_flags & MS_NODIRATIME)) - ntfs_warning(sb, "Directory atime updates are not implemented " - "yet. Disabling them."); - sb->s_flags |= MS_NOATIME | MS_NODIRATIME; -#endif +#endif /* ! NTFS_RW */ /* Allocate a new ntfs_volume and place it in sb->s_fs_info. */ sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS); vol = NTFS_SB(sb); @@ -2161,6 +2295,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) memset(vol, 0, sizeof(ntfs_volume)); vol->sb = sb; vol->upcase = NULL; + vol->attrdef = NULL; vol->mft_ino = NULL; vol->mftbmp_ino = NULL; init_rwsem(&vol->mftbmp_lock); @@ -2188,6 +2323,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) vol->fmask = 0177; vol->dmask = 0077; + unlock_kernel(); + /* Important to get the mount options dealt with now. */ if (!parse_options(vol, (char*)opt)) goto err_out_now; @@ -2225,6 +2362,9 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) */ result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data); + /* Initialize the cluster and mft allocators. */ + ntfs_setup_allocators(vol); + brelse(bh); if (!result) { @@ -2252,6 +2392,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) */ sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_time_gran = 100; + /* * Now load the metadata required for the page cache and our address * space operations to function. We do this by setting up a specialised @@ -2289,14 +2431,13 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) } } /* - * 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. + * Generate the global default upcase table if necessary. Also + * temporarily increment the number of upcase users to avoid race + * conditions with concurrent (u)mounts. */ - if (!ntfs_nr_mounts++) + if (!default_upcase) default_upcase = generate_default_upcase(); ntfs_nr_upcase_users++; - up(&ntfs_lock); /* * From now on, ignore @silent parameter. If we fail below this line, @@ -2322,6 +2463,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) } up(&ntfs_lock); sb->s_export_op = &ntfs_export_ops; + lock_kernel(); return 0; } ntfs_error(sb, "Failed to allocate root directory."); @@ -2368,10 +2510,23 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) vol->mftmirr_ino = NULL; } #endif /* NTFS_RW */ + /* Throw away the table of attribute definitions. */ + vol->attrdef_size = 0; + if (vol->attrdef) { + ntfs_free(vol->attrdef); + vol->attrdef = NULL; + } vol->upcase_len = 0; - if (vol->upcase != default_upcase) + down(&ntfs_lock); + if (vol->upcase == default_upcase) { + ntfs_nr_upcase_users--; + vol->upcase = NULL; + } + up(&ntfs_lock); + if (vol->upcase) { ntfs_free(vol->upcase); - vol->upcase = NULL; + vol->upcase = NULL; + } if (vol->nls_map) { unload_nls(vol->nls_map); vol->nls_map = NULL; @@ -2379,11 +2534,10 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) /* 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. + * Decrease the number of upcase users and destroy the global default + * upcase table if necessary. */ down(&ntfs_lock); - ntfs_nr_mounts--; if (!--ntfs_nr_upcase_users && default_upcase) { ntfs_free(default_upcase); default_upcase = NULL; @@ -2413,6 +2567,7 @@ iput_tmp_ino_err_out_now: } /* Errors at this stage are irrelevant. */ err_out_now: + lock_kernel(); sb->s_fs_info = NULL; kfree(vol); ntfs_debug("Failed, returning -EINVAL."); @@ -2448,13 +2603,6 @@ static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep, kmem_cache_t *ntfs_attr_ctx_cache; kmem_cache_t *ntfs_index_ctx_cache; -/* A global default upcase table and a corresponding reference count. */ -wchar_t *default_upcase = NULL; -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); @@ -2509,7 +2657,7 @@ static int __init init_ntfs_fs(void) goto ictx_err_out; } ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name, - sizeof(attr_search_context), 0 /* offset */, + sizeof(ntfs_attr_search_ctx), 0 /* offset */, SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */); if (!ntfs_attr_ctx_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", @@ -2528,7 +2676,7 @@ static int __init init_ntfs_fs(void) ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name, sizeof(ntfs_inode), 0, - SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, NULL, NULL); + SLAB_RECLAIM_ACCOUNT, NULL, NULL); if (!ntfs_inode_cache) { printk(KERN_CRIT "NTFS: Failed to create %s!\n", ntfs_inode_cache_name); @@ -2612,9 +2760,10 @@ static void __exit exit_ntfs_fs(void) MODULE_AUTHOR("Anton Altaparmakov "); MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2004 Anton Altaparmakov"); +MODULE_VERSION(NTFS_VERSION); MODULE_LICENSE("GPL"); #ifdef DEBUG -MODULE_PARM(debug_msgs, "i"); +module_param(debug_msgs, bool, 0); MODULE_PARM_DESC(debug_msgs, "Enable debug messages."); #endif