remove BKL from inode_setattr
Subsystems (4)
PATCH 1/1 remove BKL from inode_setattr
Since April 05 of this year we've been holding the BKL across the vmtruncate call out of inode_setattr(). By accident it seems.
This does not affect unlink(). It affects ftruncate() and open(O_TRUNC).
Given that the drop_inode() path does not take the BKL, I would suggest that it is safe to assume that the various filesystem's truncate code is safe without this additional VFS-level lock_kernel(), and that it can be simply removed.
Sound sane?
fs/attr.c renamed from fs/attr.c~truncate-bkl +0 -2
@@ -67,7 +67,6 @@ int inode_setattr(struct inode * inode,unsigned int ia_valid = attr->ia_valid;int error =0 ; -lock_kernel ();if (ia_valid &ATTR_SIZE ) { error =vmtruncate (inode, attr->ia_size);if (error)
@@ -91,7 +90,6 @@ int inode_setattr(struct inode * inode, }mark_inode_dirty (inode); out: -unlock_kernel ();return error; }
.
Quoted 3 lines · Andrew Morton
Since April 05 of this year we've been holding the BKL across the vmtruncate call out of
inode_setattr(). By accident it seems.
But until then, the lock_kernel was one level up in notify_change().
Quoted 1 line
This does not affect
unlink(). It affectsftruncate()andopen(O_TRUNC).
And the patch you give affects chown, chgrp, chmod, utime also:
removing a synchronization point if nothing more. Could that matter?
Quoted 4 lines
Given that the
drop_inode()path does not take the BKL, I would suggest that it is safe to assume that the various filesystem's truncate code is safe without this additional VFS-levellock_kernel(), and that it can be simply removed.
Isn't doing it when the references have gone rather easier/safer than when they remain? I'm not sure your argument holds.
Quoted 1 line
Sound sane?
Of course I want you to be right! But I don't see that you've made a strong enough case yet. Please show I'm being stupid, someone.
Hugh
Quoted 7 lines · Hugh Dickins
Quoted 3 lines · Andrew Morton
Since April 05 of this year we've been holding the BKL across the vmtruncate call out of
inode_setattr(). By accident it seems.But until then, the
lock_kernelwas one level up innotify_change().
OK.
Quoted 4 lines
Quoted 1 line
This does not affect
unlink(). It affectsftruncate()andopen(O_TRUNC).And the patch you give affects chown, chgrp, chmod, utime also:
removing a synchronization point if nothing more. Could that matter?
I don't think so. If
lock_kernel(); foo = bar; unlock_kernel();
is racy then so is
foo = bar;
Quoted 7 lines
Quoted 4 lines
Given that the
drop_inode()path does not take the BKL, I would suggest that it is safe to assume that the various filesystem's truncate code is safe without this additional VFS-levellock_kernel(), and that it can be simply removed.Isn't doing it when the references have gone rather easier/safer than when they remain? I'm not sure your argument holds.
well we hold i_sem. So races against operations against the same file are pretty much blotted out. Only reads I guess. It's races against operations on different files which are the concern. And we're already exposed to them.
The number of filsystems which do not take the bkl in truncate/setattr is in fact quite small. Here's the patch which removes all doubt:
fs/affs/file.c | 13 ++++++++----- fs/attr.c | 2 -- fs/cifs/inode.c | 7 ++++++- fs/jfs/file.c | 3 +++ fs/reiserfs/file.c | 2 ++ fs/smbfs/proc.c | 18 +++++++++++++++--- fs/sysv/itree.c | 6 +++++- fs/xfs/linux/xfs_iops.c | 11 +++++++++-- 8 files changed, 48 insertions(+), 14 deletions(-)
fs/attr.c renamed from fs/attr.c~truncate-bkl +0 -2
@@ -67,7 +67,6 @@ int inode_setattr(struct inode * inode,unsigned int ia_valid = attr->ia_valid;int error =0 ; -lock_kernel ();if (ia_valid &ATTR_SIZE ) { error =vmtruncate (inode, attr->ia_size);if (error)
@@ -91,7 +90,6 @@ int inode_setattr(struct inode * inode, }mark_inode_dirty (inode); out: -unlock_kernel ();return error; }
fs/affs/file.c renamed from fs/affs/file.c~truncate-bkl +8 -5
@@ -832,6 +832,7 @@ affs_truncate(struct inode *inode)pr_debug ("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n" , (u32 )inode->i_ino, (u32 )AFFS_I (inode)->mmu_private, (u32 )inode->i_size); +lock_kernel (); last_blk =0 ; ext =0 ;if (inode->i_size) {
@@ -847,7 +848,7 @@ affs_truncate(struct inode *inode) page =grab_cache_page (mapping, size >>PAGE_CACHE_SHIFT );if (!page) -return ; + goto out; size = (size & (PAGE_CACHE_SIZE -1 )) +1 ; res = mapping->a_ops->prepare_write (NULL , page, size, size);if (!res)
@@ -855,16 +856,16 @@ affs_truncate(struct inode *inode)unlock_page (page);page_cache_release (page);mark_inode_dirty (inode); -return ; + goto out; }else if (inode->i_size ==AFFS_I (inode)->mmu_private) -return ; + goto out;// lock cache ext_bh =affs_get_extblock (inode, ext);if (IS_ERR (ext_bh)) {affs_warning (sb,"truncate" ,"unexpected read error for ext block %u (%d)" , ext,PTR_ERR (ext_bh)); -return ; + goto out; }if (AFFS_I (inode)->i_lc) {/* clear linear cache */
@@ -910,7 +911,7 @@ affs_truncate(struct inode *inode)if (IS_ERR (ext_bh)) {affs_warning (sb,"truncate" ,"unexpected read error for last block %u (%d)" , ext,PTR_ERR (ext_bh)); -return ; + goto out; } tmp =be32_to_cpu (AFFS_DATA_HEAD (bh)->next);AFFS_DATA_HEAD (bh)->next =0 ;
@@ -936,4 +937,6 @@ affs_truncate(struct inode *inode)affs_brelse (ext_bh); }affs_free_prealloc (inode); +out: +unlock_kernel (); }
fs/cifs/inode.c renamed from fs/cifs/inode.c~truncate-bkl +6 -1
@@ -20,6 +20,7 @@*/ #include <linux/fs.h> #include <linux/stat.h> +#include <linux/smp_lock.h> #include <asm/div64.h> #include "cifsfs.h" #include "cifspdu.h"
@@ -517,6 +518,8 @@ cifs_truncate_file(struct inode *inode)struct dentry *dirent;char *full_path =NULL ; +lock_kernel (); + xid =GetXid (); cifs_sb =CIFS_SB (inode->i_sb);
@@ -527,7 +530,7 @@ cifs_truncate_file(struct inode *inode) ("Can not get pathname from empty dentry in inode 0x%p " , inode));FreeXid (xid); -return ; + goto out; } dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias);if (dirent) {
@@ -556,6 +559,8 @@ cifs_truncate_file(struct inode *inode)if (full_path)kfree (full_path);FreeXid (xid); +out: +unlock_kernel ();return ; }
fs/jfs/file.c renamed from fs/jfs/file.c~truncate-bkl +3 -0
@@ -18,6 +18,7 @@*/ #include <linux/fs.h> +#include <linux/smp_lock.h> #include "jfs_incore.h" #include "jfs_dmap.h" #include "jfs_txnmgr.h"
@@ -90,9 +91,11 @@ static void jfs_truncate(struct inode *i {jFYI (1 , ("jfs_truncate: size = 0x%lx\n" , (ulong ) ip->i_size)); +lock_kernel ();IWRITE_LOCK (ip);jfs_truncate_nolock (ip, ip->i_size);IWRITE_UNLOCK (ip); +unlock_kernel (); }static int jfs_open (struct inode *inode,struct file *file)
fs/reiserfs/file.c renamed from fs/reiserfs/file.c~truncate-bkl +2 -0
@@ -66,7 +66,9 @@ static int reiserfs_file_release (struct }static void reiserfs_vfs_truncate_file (struct inode *inode) { +lock_kernel () ;reiserfs_truncate_file (inode,1 ) ; +unlock_kernel () ; }/* Sync a reiserfs file. */
fs/smbfs/proc.c renamed from fs/smbfs/proc.c~truncate-bkl +15 -3
@@ -1740,12 +1740,17 @@ out:static int smb_proc_trunc32 (struct inode *inode,loff_t length) { +int ret; +/* * Writing 0bytes is old-SMB magic for truncating files. * MAX_NON_LFS should prevent this from being called with a too * large offset. */ -return smb_proc_write (inode, length,0 ,NULL ); +lock_kernel (); + ret =smb_proc_write (inode, length,0 ,NULL ); +unlock_kernel (); +return ret; } static int
@@ -1757,6 +1762,7 @@ smb_proc_trunc64(struct inode *inode, lochar *data;struct smb_request *req; +lock_kernel (); result = -ENOMEM ;if (! (req =smb_alloc_request (server,14 ))) goto out;
@@ -1787,14 +1793,19 @@ smb_proc_trunc64(struct inode *inode, lo out_free:smb_rput (req); out: +unlock_kernel ();return result; }static int smb_proc_trunc95 (struct inode *inode,loff_t length) { -struct smb_sb_info *server =server_from_inode (inode); -int result =smb_proc_trunc32 (inode, length); +struct smb_sb_info *server; +int result; + +lock_kernel (); + server =server_from_inode (inode); + result =smb_proc_trunc32 (inode, length);/* * win9x doesn't appear to update the size immediately.
@@ -1804,6 +1815,7 @@ smb_proc_trunc95(struct inode *inode, lo* FIXME: is this still necessary? */ smb_proc_flush (server,SMB_I (inode)->fileid); +unlock_kernel ();return result; }
fs/sysv/itree.c renamed from fs/sysv/itree.c~truncate-bkl +5 -1
@@ -373,6 +373,8 @@ void sysv_truncate (struct inode * inode S_ISLNK(inode->i_mode)))return ; +lock_kernel (); + blocksize = inode->i_sb->s_blocksize; iblock = (inode->i_size + blocksize-1 ) >> inode->i_sb->s_blocksize_bits;
@@ -381,7 +383,7 @@ void sysv_truncate (struct inode * inode n =block_to_path (inode, iblock, offsets);if (n ==0 ) -return ; + goto out;if (n ==1 ) {free_data (inode, i_data+offsets[0 ], i_data +DIRECT );
@@ -421,6 +423,8 @@ do_indirects:sysv_sync_inode (inode); elsemark_inode_dirty (inode ); +out: +unlock_kernel (); }static unsigned sysv_nblocks (struct super_block *s,loff_t size)
fs/xfs/linux/xfs_iops.c renamed from fs/xfs/linux/xfs_iops.c~truncate-bkl +9 -2
@@ -32,6 +32,7 @@#include <xfs.h> #include <linux/xattr.h> +#include <linux/smp_lock.h> /*
@@ -482,6 +483,8 @@ linvfs_setattr(int error;int flags =0 ; +lock_kernel (); +memset (&vattr,0 ,sizeof (vattr_t));if (ia_valid &ATTR_UID ) { vattr.va_mask |=AT_UID ;
@@ -521,8 +524,10 @@ linvfs_setattr( flags =ATTR_UTIME ;VOP_SETATTR (vp, &vattr, flags,NULL , error); -if (error) -return (-error);/* Positive error up from XFS */ +if (error) { + error = -error;/* Positive error up from XFS */ + goto out; + }if (ia_valid &ATTR_SIZE ) { error =vmtruncate (inode, attr->ia_size); }
@@ -531,6 +536,8 @@ linvfs_setattr(vn_revalidate (vp,0 );mark_inode_dirty_sync (inode); } +out: +unlock_kernel ();return error; }
.
Quoted 7 lines · Andrew Morton
The number of filsystems which do not take the bkl in truncate/setattr is in fact quite small. Here's the patch which removes all doubt:
Quoted 9 lines
fs/affs/file.c | 13 ++++++++----- fs/attr.c | 2 -- fs/cifs/inode.c | 7 ++++++- fs/jfs/file.c | 3 +++ fs/reiserfs/file.c | 2 ++ fs/smbfs/proc.c | 18 +++++++++++++++--- fs/sysv/itree.c | 6 +++++- fs/xfs/linux/xfs_iops.c | 11 +++++++++-- 8 files changed, 48 insertions(+), 14 deletions(-)
XFS deliberately does not take the BKL - anywhere. Our setattr code is doing its own locking. You just added the BKL to a bunch of xfs operations which do not need it. Now, vmtruncate may need it, itself, but if vmtruncate does not, then the xfs callout from vmtruncate certainly does not.
Steve
Signature · 2 lines
Steve Lord voice: +1-651-683-3511 Principal Engineer, Filesystem Software email: [email protected]
Quoted 20 lines · Steve Lord
Quoted 7 lines · Andrew Morton
The number of filsystems which do not take the bkl in truncate/setattr is in fact quite small. Here's the patch which removes all doubt:
Quoted 9 lines
fs/affs/file.c | 13 ++++++++----- fs/attr.c | 2 -- fs/cifs/inode.c | 7 ++++++- fs/jfs/file.c | 3 +++ fs/reiserfs/file.c | 2 ++ fs/smbfs/proc.c | 18 +++++++++++++++--- fs/sysv/itree.c | 6 +++++- fs/xfs/linux/xfs_iops.c | 11 +++++++++-- 8 files changed, 48 insertions(+), 14 deletions(-)
Quoted 6 lines
XFS deliberately does not take the BKL - anywhere. Our setattr code is doing its own locking. You just added the BKL to a bunch of xfs operations which do not need it. Now, vmtruncate may need it, itself, but if vmtruncate does not, then the xfs callout from vmtruncate certainly does not.
Sorry, but that is standard "bkl migration" methodology. You had it before, so you get it after. It is not my role to change XFS locking.
Anyway, I don't think these patches are going anywhere.
Quoted 10 lines · Andrew Morton
Quoted 7 lines
XFS deliberately does not take the BKL - anywhere. Our setattr code is doing its own locking. You just added the BKL to a bunch of xfs operations which do not need it. Now, vmtruncate may need it, itself, but if vmtruncate does not, then the xfs callout from vmtruncate certainly does not.
Sorry, but that is standard "bkl migration" methodology. You had it before, so you get it after. It is not my role to change XFS locking.
But you did .... my point was, XFS does not use the BKL at all, has never needed it and never will. The setattr call you added it to meant you added it to chown, chmod etc. When the BKL was migrated down below the vfs layer in all those places I deliberately did not add it to the XFS calls.
Quoted 2 lines
Anyway, I don't think these patches are going anywhere.
No problem,
Steve
Signature · 2 lines
Steve Lord voice: +1-651-683-3511 Principal Engineer, Filesystem Software email: [email protected]
Quoted 12 lines · Andrew Morton
fs/jfs/file.c renamed from fs/jfs/file.c~truncate-bkl +1
-0@@ -18,6 +18,7 @@*/ #include <linux/fs.h> +#include <linux/smp_lock.h> #include "jfs_incore.h" #include "jfs_dmap.h" #include "jfs_txnmgr.h" @@ -90,9 +91,11 @@ static void jfs_truncate(struct inode *i {
fs/jfs/file.c static void jfs_truncate(struct inode *i · line 101
Quoted 10 lines
fs/jfs/file.c renamed from fs/jfs/file.c~truncate-bkl +2
-0jFYI (1 , ("jfs_truncate: size = 0x%lx\n" , (ulong ) ip->i_size)); +lock_kernel ();IWRITE_LOCK (ip);jfs_truncate_nolock (ip, ip->i_size);IWRITE_UNLOCK (ip); +unlock_kernel (); }static int jfs_open (struct inode *inode,struct file *file)
JFS does not need the BKL. It does it's own locking.
Signature · 2 lines
David Kleikamp IBM Linux Technology Center