bk://linux-ntfs.bkbits.net/ntfs-2.6-devel aia21@cantab.net|ChangeSet|20040708120712|23156 aia21 # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/07/08 13:07:12+01:00 aia21@cantab.net # NTFS: Implement fsync, fdatasync, and msync both for files (fs/ntfs/file.c) # and directories (fs/ntfs/dir.c). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/file.c # 2004/07/08 13:07:05+01:00 aia21@cantab.net +55 -3 # Implement fsync, fdatasync, and msync for files. # # fs/ntfs/dir.c # 2004/07/08 13:07:05+01:00 aia21@cantab.net +60 -1 # Implement fsync, fdatasync, and msync for directories. # # fs/ntfs/ChangeLog # 2004/07/08 13:07:05+01:00 aia21@cantab.net +2 -0 # Update # # ChangeSet # 2004/07/08 12:13:35+01:00 aia21@cantab.net # NTFS: Change ntfs_write_inode to return 0 on success and -errno on error # and create a wrapper ntfs_write_inode_vfs that does not have a # return value and use the wrapper for the VFS super_operations # write_inode function. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/super.c # 2004/07/08 12:13:29+01:00 aia21@cantab.net +1 -1 # Change ntfs_write_inode to return 0 on success and -errno on error and # create a wrapper ntfs_write_inode_vfs that does not have a return value # and use the wrapper for the VFS super_operations write_inode function. # # fs/ntfs/inode.h # 2004/07/08 12:13:29+01:00 aia21@cantab.net +2 -1 # Change ntfs_write_inode to return 0 on success and -errno on error and # create a wrapper ntfs_write_inode_vfs that does not have a return value # and use the wrapper for the VFS super_operations write_inode function. # # fs/ntfs/inode.c # 2004/07/08 12:13:28+01:00 aia21@cantab.net +30 -4 # Change ntfs_write_inode to return 0 on success and -errno on error and # create a wrapper ntfs_write_inode_vfs that does not have a return value # and use the wrapper for the VFS super_operations write_inode function. # # ChangeSet # 2004/07/07 16:10:11+01:00 aia21@cantab.net # NTFS: Add support for readv/writev and aio_read/aio_write. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/file.c # 2004/07/07 16:10:04+01:00 aia21@cantab.net +35 -12 # Add support for readv/writev and aio_read/aio_write. # # fs/ntfs/Makefile # 2004/07/07 16:10:04+01:00 aia21@cantab.net +1 -1 # Bump version to 2.1.16-WIP. # # fs/ntfs/ChangeLog # 2004/07/07 16:10:04+01:00 aia21@cantab.net +6 -0 # Update # diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog --- a/fs/ntfs/ChangeLog 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/ChangeLog 2004-07-08 18:16:52 -07:00 @@ -26,6 +26,14 @@ - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.16 - WIP. + + - Add support for readv/writev and aio_read/aio_write (fs/ntfs/file.c). + This is done by setting the appropriate file operations pointers to + the generic helper functions provided by mm/filemap.c. + - Implement fsync, fdatasync, and msync both for files (fs/ntfs/file.c) + and directories (fs/ntfs/dir.c). + 2.1.15 - Invalidate quotas when (re)mounting read-write. - Add new element itype.index.collation_rule to the ntfs inode diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile --- a/fs/ntfs/Makefile 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/Makefile 2004-07-08 18:16:52 -07:00 @@ -6,7 +6,7 @@ index.o inode.o mft.o mst.o namei.o super.o sysctl.o unistr.o \ upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.15\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.16-WIP\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c --- a/fs/ntfs/dir.c 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/dir.c 2004-07-08 18:16:52 -07:00 @@ -1495,10 +1495,69 @@ return 0; } +#ifdef NTFS_RW + +/** + * ntfs_dir_fsync - sync a directory to disk + * @filp: directory to be synced + * @dentry: dentry describing the directory to sync + * @datasync: if non-zero only flush user data and not metadata + * + * Data integrity sync of a directory to disk. Used for fsync, fdatasync, and + * msync system calls. This function is based on file.c::ntfs_file_fsync(). + * + * Write the mft record and all associated extent mft records as well as the + * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device. + * + * If @datasync is true, we do not wait on the inode(s) to be written out + * but we always wait on the page cache pages to be written out. + * + * Note: In the past @filp could be NULL so we ignore it as we don't need it + * anyway. + * + * Locking: Caller must hold i_sem on the inode. + * + * TODO: We should probably also write all attribute/index inodes associated + * with this inode but since we have no simple way of getting to them we ignore + * this problem for now. We do write the $BITMAP attribute if it is present + * which is the important one for a directory so things are not too bad. + */ +static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, + int datasync) +{ + struct inode *vi = dentry->d_inode; + ntfs_inode *ni = NTFS_I(vi); + int err, ret; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + BUG_ON(!S_ISDIR(vi->i_mode)); + if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) + write_inode_now(ni->itype.index.bmp_ino, !datasync); + ret = ntfs_write_inode(vi, 1); + write_inode_now(vi, !datasync); + err = sync_blockdev(vi->i_sb->s_bdev); + if (unlikely(err && !ret)) + ret = err; + if (likely(!ret)) + ntfs_debug("Done."); + else + ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " + "%u.", datasync ? "data" : "", vi->i_ino, -ret); + return ret; +} + +#endif /* NTFS_RW */ + struct file_operations ntfs_dir_ops = { .llseek = generic_file_llseek, /* Seek inside directory. */ .read = generic_read_dir, /* Return -EISDIR. */ .readdir = ntfs_readdir, /* Read directory contents. */ +#ifdef NTFS_RW + .fsync = ntfs_dir_fsync, /* Sync a directory to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a kiocb. */ +#endif /* NTFS_RW */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ .open = ntfs_dir_open, /* Open directory. */ }; - diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c --- a/fs/ntfs/file.c 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/file.c 2004-07-08 18:16:52 -07:00 @@ -48,26 +48,101 @@ return generic_file_open(vi, filp); } +#ifdef NTFS_RW + +/** + * ntfs_file_fsync - sync a file to disk + * @filp: file to be synced + * @dentry: dentry describing the file to sync + * @datasync: if non-zero only flush user data and not metadata + * + * Data integrity sync of a file to disk. Used for fsync, fdatasync, and msync + * system calls. This function is inspired by fs/buffer.c::file_fsync(). + * + * If @datasync is false, write the mft record and all associated extent mft + * records as well as the $DATA attribute and then sync the block device. + * + * If @datasync is true and the attribute is non-resident, we skip the writing + * of the mft record and all associated extent mft records (this might still + * happen due to the write_inode_now() call). + * + * Also, if @datasync is true, we do not wait on the inode to be written out + * but we always wait on the page cache pages to be written out. + * + * Note: In the past @filp could be NULL so we ignore it as we don't need it + * anyway. + * + * Locking: Caller must hold i_sem on the inode. + * + * TODO: We should probably also write all attribute/index inodes associated + * with this inode but since we have no simple way of getting to them we ignore + * this problem for now. + */ +static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, + int datasync) +{ + struct inode *vi = dentry->d_inode; + int err, ret = 0; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + BUG_ON(S_ISDIR(vi->i_mode)); + if (!datasync || !NInoNonResident(NTFS_I(vi))) + ret = ntfs_write_inode(vi, 1); + write_inode_now(vi, !datasync); + err = sync_blockdev(vi->i_sb->s_bdev); + if (unlikely(err && !ret)) + ret = err; + if (likely(!ret)) + ntfs_debug("Done."); + else + ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " + "%u.", datasync ? "data" : "", vi->i_ino, -ret); + return ret; +} + +#endif /* NTFS_RW */ + struct file_operations ntfs_file_ops = { - .llseek = generic_file_llseek, /* Seek inside file. */ - .read = generic_file_read, /* Read from file. */ + .llseek = generic_file_llseek, /* Seek inside file. */ + .read = generic_file_read, /* Read from file. */ + .aio_read = generic_file_aio_read, /* Async read from file. */ + .readv = generic_file_readv, /* Read from file. */ #ifdef NTFS_RW - .write = generic_file_write, /* Write to a file. */ -#endif - .mmap = generic_file_mmap, /* Mmap file. */ - .sendfile = generic_file_sendfile,/* Zero-copy data send with the - data source being on the - ntfs partition. We don't - need to care about the data - destination. */ - .open = ntfs_file_open, /* Open file. */ + .write = generic_file_write, /* Write to file. */ + .aio_write = generic_file_aio_write, /* Async write to file. */ + .writev = generic_file_writev, /* Write to file. */ + /*.release = ,*/ /* Last file is closed. See + fs/ext2/file.c:: + ext2_release_file() for + how to use this to discard + preallocated space for + write opened files. */ + .fsync = ntfs_file_fsync, /* Sync a file to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a + kiocb. */ +#endif /* NTFS_RW */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ + .mmap = generic_file_mmap, /* Mmap file. */ + .open = ntfs_file_open, /* Open file. */ + .sendfile = generic_file_sendfile, /* Zero-copy data send with + the data source being on + the ntfs partition. We + do not need to care about + the data destination. */ + /*.sendpage = ,*/ /* Zero-copy data send with + the data destination being + on the ntfs partition. We + do not need to care about + the data source. */ }; struct inode_operations ntfs_file_inode_ops = { #ifdef NTFS_RW .truncate = ntfs_truncate, .setattr = ntfs_setattr, -#endif +#endif /* NTFS_RW */ }; struct file_operations ntfs_empty_file_ops = {}; diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/inode.c 2004-07-08 18:16:52 -07:00 @@ -2314,8 +2314,10 @@ * marking the page (and in this case mft record) dirty but we do not implement * this yet as write_mft_record() largely ignores the @sync parameter and * always performs synchronous writes. + * + * Return 0 on success and -errno on error. */ -void ntfs_write_inode(struct inode *vi, int sync) +int ntfs_write_inode(struct inode *vi, int sync) { ntfs_inode *ni = NTFS_I(vi); #if 0 @@ -2332,7 +2334,7 @@ */ if (NInoAttr(ni)) { NInoClearDirty(ni); - return; + return 0; } /* Map, pin, and lock the mft record belonging to the inode. */ m = map_mft_record(ni); @@ -2410,7 +2412,7 @@ if (unlikely(err)) goto err_out; ntfs_debug("Done."); - return; + return 0; #if 0 unm_err_out: unmap_mft_record(ni); @@ -2426,7 +2428,31 @@ "as bad. You should run chkdsk.", -err); make_bad_inode(vi); } - return; + return err; +} + +/** + * ntfs_write_inode_vfs - write out a dirty inode + * @vi: inode to write out + * @sync: if true, write out synchronously + * + * Write out a dirty inode to disk including any extent inodes if present. + * + * If @sync is true, commit the inode to disk and wait for io completion. This + * is done using write_mft_record(). + * + * If @sync is false, just schedule the write to happen but do not wait for i/o + * completion. In 2.6 kernels, scheduling usually happens just by virtue of + * marking the page (and in this case mft record) dirty but we do not implement + * this yet as write_mft_record() largely ignores the @sync parameter and + * always performs synchronous writes. + * + * This functions does not have a return value which is the required behaviour + * for the VFS super_operations ->dirty_inode function. + */ +void ntfs_write_inode_vfs(struct inode *vi, int sync) +{ + ntfs_write_inode(vi, sync); } #endif /* NTFS_RW */ diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h --- a/fs/ntfs/inode.h 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/inode.h 2004-07-08 18:16:52 -07:00 @@ -285,7 +285,8 @@ extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr); -extern void ntfs_write_inode(struct inode *vi, int sync); +extern int ntfs_write_inode(struct inode *vi, int sync); +extern void ntfs_write_inode_vfs(struct inode *vi, int sync); static inline void ntfs_commit_inode(struct inode *vi) { diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c --- a/fs/ntfs/super.c 2004-07-08 18:16:52 -07:00 +++ b/fs/ntfs/super.c 2004-07-08 18:16:52 -07:00 @@ -2050,7 +2050,7 @@ #ifdef NTFS_RW //.dirty_inode = NULL, /* VFS: Called from // __mark_inode_dirty(). */ - .write_inode = ntfs_write_inode, /* VFS: Write dirty inode to + .write_inode = ntfs_write_inode_vfs, /* VFS: Write dirty inode to disk. */ //.drop_inode = NULL, /* VFS: Called just after the // inode reference count has