bk://linux-ntfs.bkbits.net/ntfs-2.6-devel ntfs@flatcap.org|ChangeSet|20041026030920|43899 ntfs # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/10/25 11:01:14+01:00 aia21@cantab.net # NTFS: In fs/ntfs/aops.c::mark_ntfs_record_dirty(), take the # mapping->private_lock around the dirtying of the buffer heads # analagous to the way it is done in __set_page_dirty_buffers(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/aops.c # 2004/10/25 11:01:06+01:00 aia21@cantab.net +2 -0 # In mark_ntfs_record_dirty(), take the mapping->private_lock around the # dirtying of the buffer heads analagous to the way it is done in # __set_page_dirty_buffers(). # # fs/ntfs/ChangeLog # 2004/10/25 11:01:06+01:00 aia21@cantab.net +3 -0 # Update # # ChangeSet # 2004/10/25 10:54:46+01:00 aia21@cantab.net # NTFS: Add attribute definition handling helpers to fs/ntfs/attrib.[hc]: # ntfs_attr_size_bounds_check(), ntfs_attr_can_be_non_resident(), and # ntfs_attr_can_be_resident(), which in turn use the new private helper # ntfs_attr_find_in_attrdef(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/attrib.h # 2004/10/25 10:54:37+01:00 aia21@cantab.net +8 -0 # Add attribute definition handling helpers: ntfs_attr_size_bounds_check(), # ntfs_attr_can_be_non_resident(), and ntfs_attr_can_be_resident(), which in # turn use the new private helper ntfs_attr_find_in_attrdef(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/attrib.c # 2004/10/25 10:54:37+01:00 aia21@cantab.net +129 -0 # Add attribute definition handling helpers: ntfs_attr_size_bounds_check(), # ntfs_attr_can_be_non_resident(), and ntfs_attr_can_be_resident(), which in # turn use the new private helper ntfs_attr_find_in_attrdef(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/ChangeLog # 2004/10/25 10:54:37+01:00 aia21@cantab.net +4 -0 # Update # # ChangeSet # 2004/10/25 10:49:00+01:00 aia21@cantab.net # NTFS: Fix min_size and max_size definitions in ATTR_DEF structure in # fs/ntfs/layout.h to be signed. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/layout.h # 2004/10/25 10:48:51+01:00 aia21@cantab.net +2 -2 # Fix min_size and max_size definitions in ATTR_DEF structure to be signed. # # fs/ntfs/ChangeLog # 2004/10/25 10:48:51+01:00 aia21@cantab.net +2 -0 # Update # # ChangeSet # 2004/10/25 10:46:39+01:00 aia21@cantab.net # NTFS: - Change fs/ntfs/inode.c::ntfs_truncate() to return an error code # instead of void and provide a helper ntfs_truncate_vfs() for the # vfs ->truncate method. # - Add a new ntfs inode flag NInoTruncateFailed() and modify # fs/ntfs/inode.c::ntfs_truncate() to set and clear it appropriately. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/inode.h # 2004/10/25 10:46:30+01:00 aia21@cantab.net +4 -1 # - Change fs/ntfs/inode.c::ntfs_truncate() to return an error code # instead of void and provide a helper ntfs_truncate_vfs() for the # vfs ->truncate method. # - Add a new ntfs inode flag NInoTruncateFailed() and modify # fs/ntfs/inode.c::ntfs_truncate() to set and clear it appropriately. # # fs/ntfs/inode.c # 2004/10/25 10:46:30+01:00 aia21@cantab.net +19 -3 # - Change fs/ntfs/inode.c::ntfs_truncate() to return an error code # instead of void and provide a helper ntfs_truncate_vfs() for the # vfs ->truncate method. # - Add a new ntfs inode flag NInoTruncateFailed() and modify # fs/ntfs/inode.c::ntfs_truncate() to set and clear it appropriately. # # fs/ntfs/file.c # 2004/10/25 10:46:30+01:00 aia21@cantab.net +1 -1 # - Change fs/ntfs/inode.c::ntfs_truncate() to return an error code # instead of void and provide a helper ntfs_truncate_vfs() for the # vfs ->truncate method. # - Add a new ntfs inode flag NInoTruncateFailed() and modify # fs/ntfs/inode.c::ntfs_truncate() to set and clear it appropriately. # # fs/ntfs/ChangeLog # 2004/10/25 10:46:30+01:00 aia21@cantab.net +5 -0 # Update # # ChangeSet # 2004/10/25 10:41:30+01:00 aia21@cantab.net # NTFS: Add fs/ntfs/aops.c to list of providers for ->b_end_io method in # Documentation/filesystems/Locking. # # Signed-off-by: Anton Altaparmakov # # Documentation/filesystems/Locking # 2004/10/25 10:41:20+01:00 aia21@cantab.net +2 -2 # Add fs/ntfs/aops.c to list of providers for ->b_end_io method. # # ChangeSet # 2004/10/21 12:31:59+01:00 aia21@cantab.net # NTFS: Improve error handling in fs/ntfs/inode.c::ntfs_truncate(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/inode.c # 2004/10/21 12:31:50+01:00 aia21@cantab.net +29 -20 # Improve error handling in ntfs_truncate(). # # fs/ntfs/Makefile # 2004/10/21 12:31:50+01:00 aia21@cantab.net +1 -1 # Start 2.1.22-WIP. # # fs/ntfs/ChangeLog # 2004/10/21 12:31:50+01:00 aia21@cantab.net +4 -0 # Update # # ChangeSet # 2004/10/20 13:14:44+01:00 aia21@cantab.net # NTFS: Fix two typos in Documentation/filesystems/ntfs.txt. # # Thanks to Richard Russon for pointing them out. # # Signed-off-by: Anton Altaparmakov # # Documentation/filesystems/ntfs.txt # 2004/10/20 13:14:35+01:00 aia21@cantab.net +2 -2 # Fix typos. # diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking --- a/Documentation/filesystems/Locking 2004-10-26 18:38:28 -07:00 +++ b/Documentation/filesystems/Locking 2004-10-26 18:38:28 -07:00 @@ -317,8 +317,8 @@ locking rules: called from interrupts. In other words, extreme care is needed here. bh is locked, but that's all warranties we have here. Currently only RAID1, -highmem and fs/buffer.c are providing these. Block devices call this method -upon the IO completion. +highmem, fs/buffer.c, and fs/ntfs/aops.c are providing these. Block devices +call this method upon the IO completion. --------------------------- block_device_operations ----------------------- prototypes: diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt --- a/Documentation/filesystems/ntfs.txt 2004-10-26 18:38:28 -07:00 +++ b/Documentation/filesystems/ntfs.txt 2004-10-26 18:38:28 -07:00 @@ -258,10 +258,10 @@ $ ./ldminfo --dump /dev/hda This would dump the LDM database found on /dev/hda which describes all of your -dinamic disks and all the volumes on them. At the bottom you will see the +dynamic disks and all the volumes on them. At the bottom you will see the VOLUME DEFINITIONS section which is all you really need. You may need to look further above to determine which of the disks in the volume definitions is -which device in Linux. Hint: Run ldminfo on each of your dinamic disks and +which device in Linux. Hint: Run ldminfo on each of your dynamic disks and look at the Disk Id close to the top of the output for each (the PRIVATE HEADER section). You can then find these Disk Ids in the VBLK DATABASE section in the components where you will get the LDM Name for the disk that is found in diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog --- a/fs/ntfs/ChangeLog 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/ChangeLog 2004-10-26 18:38:28 -07:00 @@ -21,6 +21,24 @@ - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.22-WIP + + - Improve error handling in fs/ntfs/inode.c::ntfs_truncate(). + - Change fs/ntfs/inode.c::ntfs_truncate() to return an error code + instead of void and provide a helper ntfs_truncate_vfs() for the + vfs ->truncate method. + - Add a new ntfs inode flag NInoTruncateFailed() and modify + fs/ntfs/inode.c::ntfs_truncate() to set and clear it appropriately. + - Fix min_size and max_size definitions in ATTR_DEF structure in + fs/ntfs/layout.h to be signed. + - Add attribute definition handling helpers to fs/ntfs/attrib.[hc]: + ntfs_attr_size_bounds_check(), ntfs_attr_can_be_non_resident(), and + ntfs_attr_can_be_resident(), which in turn use the new private helper + ntfs_attr_find_in_attrdef(). + - In fs/ntfs/aops.c::mark_ntfs_record_dirty(), take the + mapping->private_lock around the dirtying of the buffer heads + analagous to the way it is done in __set_page_dirty_buffers(). + 2.1.21 - Fix some races and bugs, rewrite mft write code, add mft allocator. - Implement extent mft record deallocation diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile --- a/fs/ntfs/Makefile 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/Makefile 2004-10-26 18:38:28 -07:00 @@ -6,7 +6,7 @@ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.21\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.22-WIP\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c --- a/fs/ntfs/aops.c 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/aops.c 2004-10-26 18:38:28 -07:00 @@ -2158,6 +2158,7 @@ } end = ofs + ni->itype.index.block_size; bh_size = ni->vol->sb->s_blocksize; + spin_lock(&page->mapping->private_lock); bh = head = page_buffers(page); do { bh_ofs = bh_offset(bh); @@ -2167,6 +2168,7 @@ break; set_buffer_dirty(bh); } while ((bh = bh->b_this_page) != head); + spin_unlock(&page->mapping->private_lock); __set_page_dirty_nobuffers(page); } diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c --- a/fs/ntfs/attrib.c 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/attrib.c 2004-10-26 18:38:28 -07:00 @@ -24,8 +24,10 @@ #include "attrib.h" #include "debug.h" +#include "layout.h" #include "mft.h" #include "ntfs.h" +#include "types.h" /** * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode @@ -947,6 +949,133 @@ unmap_extent_mft_record(ctx->ntfs_ino); kmem_cache_free(ntfs_attr_ctx_cache, ctx); return; +} + +/** + * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to find + * + * Search for the attribute definition record corresponding to the attribute + * @type in the $AttrDef system file. + * + * Return the attribute type definition record if found and NULL if not found. + */ +static ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, + const ATTR_TYPE type) +{ + ATTR_DEF *ad; + + BUG_ON(!vol->attrdef); + BUG_ON(!type); + for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < + vol->attrdef_size && ad->type; ++ad) { + /* We have not found it yet, carry on searching. */ + if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type))) + continue; + /* We found the attribute; return it. */ + if (likely(ad->type == type)) + return ad; + /* We have gone too far already. No point in continuing. */ + break; + } + /* Attribute not found. */ + ntfs_debug("Attribute type 0x%x not found in $AttrDef.", + le32_to_cpu(type)); + return NULL; +} + +/** + * ntfs_attr_size_bounds_check - check a size of an attribute type for validity + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to check + * @size: size which to check + * + * Check whether the @size in bytes is valid for an attribute of @type on the + * ntfs volume @vol. This information is obtained from $AttrDef system file. + * + * Return 0 if valid, -ERANGE if not valid, or -ENOENT if the attribute is not + * listed in $AttrDef. + */ +int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPE type, + const s64 size) +{ + ATTR_DEF *ad; + + BUG_ON(size < 0); + /* + * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not + * listed in $AttrDef. + */ + if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024)) + return -ERANGE; + /* Get the $AttrDef entry for the attribute @type. */ + ad = ntfs_attr_find_in_attrdef(vol, type); + if (unlikely(!ad)) + return -ENOENT; + /* Do the bounds check. */ + if (((sle64_to_cpu(ad->min_size) > 0) && + size < sle64_to_cpu(ad->min_size)) || + ((sle64_to_cpu(ad->max_size) > 0) && size > + sle64_to_cpu(ad->max_size))) + return -ERANGE; + return 0; +} + +/** + * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to check + * + * Check whether the attribute of @type on the ntfs volume @vol is allowed to + * be non-resident. This information is obtained from $AttrDef system file. + * + * Return 0 if the attribute is allowed to be non-resident, -EPERM if not, or + * -ENOENT if the attribute is not listed in $AttrDef. + */ +int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type) +{ + ATTR_DEF *ad; + + /* + * $DATA is always allowed to be non-resident even if $AttrDef does not + * specify this in the flags of the $DATA attribute definition record. + */ + if (type == AT_DATA) + return 0; + /* Find the attribute definition record in $AttrDef. */ + ad = ntfs_attr_find_in_attrdef(vol, type); + if (unlikely(!ad)) + return -ENOENT; + /* Check the flags and return the result. */ + if (ad->flags & CAN_BE_NON_RESIDENT) + return 0; + return -EPERM; +} + +/** + * ntfs_attr_can_be_resident - check if an attribute can be resident + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to check + * + * Check whether the attribute of @type on the ntfs volume @vol is allowed to + * be resident. This information is derived from our ntfs knowledge and may + * not be completely accurate, especially when user defined attributes are + * present. Basically we allow everything to be resident except for index + * allocation and $EA attributes. + * + * Return 0 if the attribute is allowed to be non-resident and -EPERM if not. + * + * Warning: In the system file $MFT the attribute $Bitmap must be non-resident + * otherwise windows will not boot (blue screen of death)! We cannot + * check for this here as we do not know which inode's $Bitmap is + * being asked about so the caller needs to special case this. + */ +int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type) +{ + if (type != AT_INDEX_ALLOCATION && type != AT_EA) + return 0; + return -EPERM; } /** diff -Nru a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h --- a/fs/ntfs/attrib.h 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/attrib.h 2004-10-26 18:38:28 -07:00 @@ -29,6 +29,7 @@ #include "layout.h" #include "inode.h" #include "runlist.h" +#include "volume.h" /** * ntfs_attr_search_ctx - used in attribute search functions @@ -83,6 +84,13 @@ extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec); extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx); + +extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol, + const ATTR_TYPE type, const s64 size); +extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, + const ATTR_TYPE type); +extern int ntfs_attr_can_be_resident(const ntfs_volume *vol, + const ATTR_TYPE type); extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c --- a/fs/ntfs/file.c 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/file.c 2004-10-26 18:38:28 -07:00 @@ -145,7 +145,7 @@ struct inode_operations ntfs_file_inode_ops = { #ifdef NTFS_RW - .truncate = ntfs_truncate, + .truncate = ntfs_truncate_vfs, .setattr = ntfs_setattr, #endif /* NTFS_RW */ }; diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/inode.c 2004-10-26 18:38:28 -07:00 @@ -2263,68 +2263,93 @@ * This implies for us that @vi is a file inode rather than a directory, index, * or attribute inode as well as that @vi is a base inode. * + * Returns 0 on success or -errno on error. + * * Called with ->i_sem held. In all but one case ->i_alloc_sem is held for * writing. The only case where ->i_alloc_sem is not held is * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called * with the current i_size as the offset which means that it is a noop as far * as ntfs_truncate() is concerned. */ -void ntfs_truncate(struct inode *vi) +int ntfs_truncate(struct inode *vi) { ntfs_inode *ni = NTFS_I(vi); + ntfs_volume *vol = ni->vol; ntfs_attr_search_ctx *ctx; MFT_RECORD *m; + const char *te = " Leaving file length out of sync with i_size."; int err; + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); BUG_ON(NInoAttr(ni)); BUG_ON(ni->nr_extents < 0); m = map_mft_record(ni); if (IS_ERR(m)) { + err = PTR_ERR(m); ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " - "(error code %ld).", vi->i_ino, PTR_ERR(m)); - if (PTR_ERR(m) != ENOMEM) - make_bad_inode(vi); - return; + "(error code %d).%s", vi->i_ino, err, te); + ctx = NULL; + m = NULL; + goto err_out; } ctx = ntfs_attr_get_search_ctx(ni, m); if (unlikely(!ctx)) { - ntfs_error(vi->i_sb, "Failed to allocate a search context: " - "Not enough memory"); - // FIXME: We can't report an error code upstream. So what do - // we do?!? make_bad_inode() seems a bit harsh... - unmap_mft_record(ni); - return; + ntfs_error(vi->i_sb, "Failed to allocate a search context for " + "inode 0x%lx (not enough memory).%s", + vi->i_ino, te); + err = -ENOMEM; + goto err_out; } err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) { - if (err == -ENOENT) { + if (err == -ENOENT) ntfs_error(vi->i_sb, "Open attribute is missing from " "mft record. Inode 0x%lx is corrupt. " "Run chkdsk.", vi->i_ino); - make_bad_inode(vi); - } else { + else ntfs_error(vi->i_sb, "Failed to lookup attribute in " "inode 0x%lx (error code %d).", vi->i_ino, err); - // FIXME: We can't report an error code upstream. So - // what do we do?!? make_bad_inode() seems a bit - // harsh... - } - goto out; + goto err_out; } /* If the size has not changed there is nothing to do. */ if (ntfs_attr_size(ctx->attr) == i_size_read(vi)) - goto out; + goto done; // TODO: Implement the truncate... ntfs_error(vi->i_sb, "Inode size has changed but this is not " "implemented yet. Resetting inode size to old value. " " This is most likely a bug in the ntfs driver!"); i_size_write(vi, ntfs_attr_size(ctx->attr)); -out: +done: ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni); - return; + ntfs_debug("Done."); + NInoClearTruncateFailed(ni); + return 0; +err_out: + if (err != -ENOMEM) { + NVolSetErrors(vol); + make_bad_inode(vi); + } + if (ctx) + ntfs_attr_put_search_ctx(ctx); + if (m) + unmap_mft_record(ni); + NInoSetTruncateFailed(ni); + return err; +} + +/** + * ntfs_truncate_vfs - wrapper for ntfs_truncate() that has no return value + * @vi: inode for which the i_size was changed + * + * Wrapper for ntfs_truncate() that has no return value. + * + * See ntfs_truncate() description above for details. + */ +void ntfs_truncate_vfs(struct inode *vi) { + ntfs_truncate(vi); } /** diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h --- a/fs/ntfs/inode.h 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/inode.h 2004-10-26 18:38:28 -07:00 @@ -165,6 +165,7 @@ NI_Sparse, /* 1: Unnamed data attr is sparse (f). 1: Create sparse files by default (d). 1: Attribute is sparse (a). */ + NI_TruncateFailed, /* 1: Last ntfs_truncate() call failed. */ } ntfs_inode_state_bits; /* @@ -216,6 +217,7 @@ NINO_FNS(Compressed) NINO_FNS(Encrypted) NINO_FNS(Sparse) +NINO_FNS(TruncateFailed) /* * The full structure containing a ntfs_inode and a vfs struct inode. Used for @@ -300,7 +302,8 @@ #ifdef NTFS_RW -extern void ntfs_truncate(struct inode *vi); +extern int ntfs_truncate(struct inode *vi); +extern void ntfs_truncate_vfs(struct inode *vi); extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr); diff -Nru a/fs/ntfs/layout.h b/fs/ntfs/layout.h --- a/fs/ntfs/layout.h 2004-10-26 18:38:28 -07:00 +++ b/fs/ntfs/layout.h 2004-10-26 18:38:28 -07:00 @@ -589,8 +589,8 @@ FIXME: What does it mean? (AIA) */ /* 88*/ COLLATION_RULE collation_rule; /* Default collation rule. */ /* 8c*/ ATTR_DEF_FLAGS flags; /* Flags describing the attribute. */ -/* 90*/ le64 min_size; /* Optional minimum attribute size. */ -/* 98*/ le64 max_size; /* Maximum size of attribute. */ +/* 90*/ sle64 min_size; /* Optional minimum attribute size. */ +/* 98*/ sle64 max_size; /* Maximum size of attribute. */ /* sizeof() = 0xa0 or 160 bytes */ } __attribute__ ((__packed__)) ATTR_DEF;