reiserfs locking patchset
cover reiserfs locking patchset
This patchset untangles some of the locking in reiserfs. It has seen more testing as part of the maintenance cycle in SLE 11 SP2.
- We push the write lock out of the xattr code. It doesn't need it and we can simplify locking by releasing and reacquiring the locks around the xattr calls.
- Handle nested locks properly. There's confusion on when a lock is nested, when it's not, and how to drop it across schedules like the BKL it is modeled after. We make the distinction between taking/releasing the lock and when to drop it for schedules and simplify the logic. This fixes a number of deadlocks that happen because the intention was to drop the write lock but it really only decremented the use count.
- Fix the deadlocks with the quota code. This involves dropping the write lock before quota calls and reacquring it afterwards. Without this patch reiserfs quotas are essentially unusable.
Jan - This series is in the for-3.12 branch of git.kernel.org:/pub/scm/linux/kernel/git/jeffm/linux-reiserfs.git
Thanks.
-Jeff
Signature · 2 lines
Jeff Mahoney SuSE Labs
PATCH 1/3 reiserfs: locking, push write lock out of xattr code
The reiserfs xattr code doesn't need the write lock and sleeps all over the place. We can simplify the locking by releasing it and reacquiring after the xattr call.
--- fs/reiserfs/inode.c | 37 ++++++++++++++++++++----------------- fs/reiserfs/super.c | 48 +++++++++++++++++++++++------------------------- fs/reiserfs/xattr.c | 46 +++++++++++++++++----------------------------- fs/reiserfs/xattr_acl.c | 16 ++++++++++------ 4 files changed, 70 insertions(+), 77 deletions(-)
fs/reiserfs/inode.c +20 -17
@@ -30,7 +30,6 @@ void reiserfs_evict_inode(struct inode *JOURNAL_PER_BALANCE_CNT *2 +2 *REISERFS_QUOTA_INIT_BLOCKS (inode->i_sb);struct reiserfs_transaction_handle th; -int depth;int err;if (!inode->i_nlink && !is_bad_inode (inode))
@@ -40,12 +39,14 @@ void reiserfs_evict_inode(struct inode *if (inode->i_nlink) goto no_delete; - depth =reiserfs_write_lock_once (inode->i_sb); -/* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ if (!(inode->i_state &I_NEW ) &&INODE_PKEY (inode)->k_objectid !=0 ) {/* also handles bad_inode case */ +int depth; +reiserfs_delete_xattrs (inode); + depth =reiserfs_write_lock_once (inode->i_sb); +if (journal_begin (&th, inode->i_sb, jbegin_count)) goto out;reiserfs_update_inode_transaction (inode);
@@ -72,12 +73,12 @@ void reiserfs_evict_inode(struct inode */* all items of file are deleted, so we can remove "save" link */ remove_save_link (inode,0 /* not truncate */ );/* we can't do anything * about an error here */ +out: +reiserfs_write_unlock_once (inode->i_sb, depth); }else {/* no object items are in the tree */ ; } - out: -reiserfs_write_unlock_once (inode->i_sb, depth);clear_inode (inode);/* note this must go after the journal_end to prevent deadlock */ dquot_drop (inode); inode->i_blocks =0 ;
@@ -1941,7 +1942,9 @@ int reiserfs_new_inode(struct reiserfs_t }if (reiserfs_posixacl (inode->i_sb)) { +reiserfs_write_unlock (inode->i_sb); retval =reiserfs_inherit_default_acl (th, dir, dentry, inode); +reiserfs_write_lock (inode->i_sb);if (retval) { err = retval;reiserfs_check_path (&path_to_key);
@@ -1956,7 +1959,9 @@ int reiserfs_new_inode(struct reiserfs_t inode->i_flags |=S_PRIVATE ;if (security->name) { +reiserfs_write_unlock (inode->i_sb); retval =reiserfs_security_write (th, inode, security); +reiserfs_write_lock (inode->i_sb);if (retval) { err = retval;reiserfs_check_path (&path_to_key);
@@ -3129,6 +3134,7 @@ int reiserfs_setattr(struct dentry *dent*/ if (get_inode_item_key_version (inode) ==KEY_FORMAT_3_5 && attr->ia_size >MAX_NON_LFS ) { +reiserfs_write_unlock_once (inode->i_sb, depth); error = -EFBIG ; goto out; }
@@ -3150,8 +3156,10 @@ int reiserfs_setattr(struct dentry *dentif (err) error = err; } -if (error) +if (error) { +reiserfs_write_unlock_once (inode->i_sb, depth); goto out; + }/* * file size is changed, ctime and mtime are * to be updated
@@ -3159,10 +3167,12 @@ int reiserfs_setattr(struct dentry *dent attr->ia_valid |= (ATTR_MTIME |ATTR_CTIME ); } } +reiserfs_write_unlock_once (inode->i_sb, depth);if ((((attr->ia_valid &ATTR_UID ) && (from_kuid (&init_user_ns, attr->ia_uid) & ~0xffff )) || ((attr->ia_valid &ATTR_GID ) && (from_kgid (&init_user_ns, attr->ia_gid) & ~0xffff ))) && (get_inode_sd_version (inode) ==STAT_DATA_V1 )) { +reiserfs_write_unlock_once (inode->i_sb, depth);/* stat data of format v3.5 has 16 bit uid and gid */ error = -EINVAL ; goto out;
@@ -3183,14 +3193,16 @@ int reiserfs_setattr(struct dentry *dentreturn error;/* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ + depth =reiserfs_write_lock_once (inode->i_sb); error =journal_begin (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock_once (inode->i_sb, depth);if (error) goto out; -reiserfs_write_unlock_once (inode->i_sb, depth); error =dquot_transfer (inode, attr); depth =reiserfs_write_lock_once (inode->i_sb);if (error) {journal_end (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock_once (inode->i_sb, depth); goto out; }
@@ -3202,17 +3214,11 @@ int reiserfs_setattr(struct dentry *dent inode->i_gid = attr->ia_gid;mark_inode_dirty (inode); error =journal_end (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock_once (inode->i_sb, depth);if (error) goto out; } -/* -* Relax the lock here, as it might truncate the -* inode pages and wait for inode pages locks. -* To release such page lock, the owner needs the -* reiserfs lock -*/ -reiserfs_write_unlock_once (inode->i_sb, depth);if ((attr->ia_valid &ATTR_SIZE ) && attr->ia_size !=i_size_read (inode)) { error =inode_newsize_ok (inode, attr->ia_size);
@@ -3226,7 +3232,6 @@ int reiserfs_setattr(struct dentry *dentsetattr_copy (inode, attr);mark_inode_dirty (inode); } - depth =reiserfs_write_lock_once (inode->i_sb);if (!error &&reiserfs_posixacl (inode->i_sb)) {if (attr->ia_valid &ATTR_MODE )
@@ -3234,8 +3239,6 @@ int reiserfs_setattr(struct dentry *dent } out: -reiserfs_write_unlock_once (inode->i_sb, depth); -return error; }
fs/reiserfs/super.c +23 -25
135 lines not on this page · raw message
fs/reiserfs/xattr.c +17 -29
163 lines not on this page · raw message
fs/reiserfs/xattr_acl.c +10 -6
@@ -49,13 +49,15 @@ posix_acl_set(struct dentry *dentry, conreiserfs_write_lock (inode->i_sb); error =journal_begin (&th, inode->i_sb, jcreate_blocks); +reiserfs_write_unlock (inode->i_sb);if (error ==0 ) { error =reiserfs_set_acl (&th, inode, type, acl); +reiserfs_write_lock (inode->i_sb); error2 =journal_end (&th, inode->i_sb, jcreate_blocks); +reiserfs_write_unlock (inode->i_sb);if (error2) error = error2; } -reiserfs_write_unlock (inode->i_sb); release_and_out:posix_acl_release (acl);
@@ -435,12 +437,14 @@ int reiserfs_cache_default_acl(struct inreturn nblocks; } +/* +* Called under i_mutex +*/ int reiserfs_acl_chmod (struct inode *inode) {struct reiserfs_transaction_handle th;struct posix_acl *acl;size_t size; -int depth;int error;if (IS_PRIVATE (inode))
@@ -454,9 +458,7 @@ int reiserfs_acl_chmod(struct inode *inoreturn 0 ; } -reiserfs_write_unlock (inode->i_sb); acl =reiserfs_get_acl (inode,ACL_TYPE_ACCESS ); -reiserfs_write_lock (inode->i_sb);if (!acl)return 0 ;if (IS_ERR (acl))
@@ -466,16 +468,18 @@ int reiserfs_acl_chmod(struct inode *inoreturn error; size =reiserfs_xattr_nblocks (inode,reiserfs_acl_size (acl->a_count)); - depth =reiserfs_write_lock_once (inode->i_sb); +reiserfs_write_lock (inode->i_sb); error =journal_begin (&th, inode->i_sb, size *2 ); +reiserfs_write_unlock (inode->i_sb);if (!error) {int error2; error =reiserfs_set_acl (&th, inode,ACL_TYPE_ACCESS , acl); +reiserfs_write_lock (inode->i_sb); error2 =journal_end (&th, inode->i_sb, size *2 ); +reiserfs_write_unlock (inode->i_sb);if (error2) error = error2; } -reiserfs_write_unlock_once (inode->i_sb, depth);posix_acl_release (acl);return error; }
Re: [patch 1/3] reiserfs: locking, push write lock out of xattr code
Quoted 97 lines · On 8/5/13 5:53 PM, [email protected] wrote:
The reiserfs xattr code doesn't need the write lock and sleeps all over the place. We can simplify the locking by releasing it and reacquiring after the xattr call.
Signed-off-by Jeff Mahoney <[email protected]>--- fs/reiserfs/inode.c | 37 ++++++++++++++++++++----------------- fs/reiserfs/super.c | 48 +++++++++++++++++++++++------------------------- fs/reiserfs/xattr.c | 46 +++++++++++++++++----------------------------- fs/reiserfs/xattr_acl.c | 16 ++++++++++------ 4 files changed, 70 insertions(+), 77 deletions(-)fs/reiserfs/inode.c +14
-6@@ -30,7 +30,6 @@ void reiserfs_evict_inode(struct inode *JOURNAL_PER_BALANCE_CNT *2 +2 *REISERFS_QUOTA_INIT_BLOCKS (inode->i_sb);struct reiserfs_transaction_handle th; -int depth;int err;if (!inode->i_nlink && !is_bad_inode (inode))@@ -40,12 +39,14 @@ void reiserfs_evict_inode(struct inode *if (inode->i_nlink) goto no_delete; - depth =reiserfs_write_lock_once (inode->i_sb); -/* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ if (!(inode->i_state &I_NEW ) &&INODE_PKEY (inode)->k_objectid !=0 ) {/* also handles bad_inode case */ +int depth; +reiserfs_delete_xattrs (inode); + depth =reiserfs_write_lock_once (inode->i_sb); +if (journal_begin (&th, inode->i_sb, jbegin_count)) goto out;reiserfs_update_inode_transaction (inode);@@ -72,12 +73,12 @@ void reiserfs_evict_inode(struct inode */* all items of file are deleted, so we can remove "save" link */ remove_save_link (inode,0 /* not truncate */ );/* we can't do anything * about an error here */ +out: +reiserfs_write_unlock_once (inode->i_sb, depth); }else {/* no object items are in the tree */ ; } - out: -reiserfs_write_unlock_once (inode->i_sb, depth);clear_inode (inode);/* note this must go after the journal_end to prevent deadlock */ dquot_drop (inode); inode->i_blocks =0 ;@@ -1941,7 +1942,9 @@ int reiserfs_new_inode(struct reiserfs_t }if (reiserfs_posixacl (inode->i_sb)) { +reiserfs_write_unlock (inode->i_sb); retval =reiserfs_inherit_default_acl (th, dir, dentry, inode); +reiserfs_write_lock (inode->i_sb);if (retval) { err = retval;reiserfs_check_path (&path_to_key);@@ -1956,7 +1959,9 @@ int reiserfs_new_inode(struct reiserfs_t inode->i_flags |=S_PRIVATE ;if (security->name) { +reiserfs_write_unlock (inode->i_sb); retval =reiserfs_security_write (th, inode, security); +reiserfs_write_lock (inode->i_sb);if (retval) { err = retval;reiserfs_check_path (&path_to_key);@@ -3129,6 +3134,7 @@ int reiserfs_setattr(struct dentry *dent*/ if (get_inode_item_key_version (inode) ==KEY_FORMAT_3_5 && attr->ia_size >MAX_NON_LFS ) { +reiserfs_write_unlock_once (inode->i_sb, depth); error = -EFBIG ; goto out; }@@ -3150,8 +3156,10 @@ int reiserfs_setattr(struct dentry *dentif (err) error = err; } -if (error) +if (error) { +reiserfs_write_unlock_once (inode->i_sb, depth); goto out; + }/* * file size is changed, ctime and mtime are * to be updated @@ -3159,10 +3167,12 @@ int reiserfs_setattr(struct dentry *dent attr->ia_valid |= (ATTR_MTIME |ATTR_CTIME ); }
fs/reiserfs/inode.c int reiserfs_setattr(struct dentry *dent · line 3178
Quoted 10 lines
fs/reiserfs/inode.c +2
-0} +reiserfs_write_unlock_once (inode->i_sb, depth);if ((((attr->ia_valid &ATTR_UID ) && (from_kuid (&init_user_ns, attr->ia_uid) & ~0xffff )) || ((attr->ia_valid &ATTR_GID ) && (from_kgid (&init_user_ns, attr->ia_gid) & ~0xffff ))) && (get_inode_sd_version (inode) ==STAT_DATA_V1 )) { +reiserfs_write_unlock_once (inode->i_sb, depth);/* stat data of format v3.5 has 16 bit uid and gid */ error = -EINVAL ; goto out;
Oops. This was an old version of the patch. This will cause a double unlock.
-Jeff
Quoted 448 lines
fs/reiserfs/inode.c +4
-11@@ -3183,14 +3193,16 @@ int reiserfs_setattr(struct dentry *dentreturn error;/* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ + depth =reiserfs_write_lock_once (inode->i_sb); error =journal_begin (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock_once (inode->i_sb, depth);if (error) goto out; -reiserfs_write_unlock_once (inode->i_sb, depth); error =dquot_transfer (inode, attr); depth =reiserfs_write_lock_once (inode->i_sb);if (error) {journal_end (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock_once (inode->i_sb, depth); goto out; }@@ -3202,17 +3214,11 @@ int reiserfs_setattr(struct dentry *dent inode->i_gid = attr->ia_gid;mark_inode_dirty (inode); error =journal_end (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock_once (inode->i_sb, depth);if (error) goto out; } -/* -* Relax the lock here, as it might truncate the -* inode pages and wait for inode pages locks. -* To release such page lock, the owner needs the -* reiserfs lock -*/ -reiserfs_write_unlock_once (inode->i_sb, depth);if ((attr->ia_valid &ATTR_SIZE ) && attr->ia_size !=i_size_read (inode)) { error =inode_newsize_ok (inode, attr->ia_size);@@ -3226,7 +3232,6 @@ int reiserfs_setattr(struct dentry *dentsetattr_copy (inode, attr);mark_inode_dirty (inode); } - depth =reiserfs_write_lock_once (inode->i_sb);if (!error &&reiserfs_posixacl (inode->i_sb)) {if (attr->ia_valid &ATTR_MODE )@@ -3234,8 +3239,6 @@ int reiserfs_setattr(struct dentry *dent } out: -reiserfs_write_unlock_once (inode->i_sb, depth); -return error; }fs/reiserfs/super.c +23
-25@@ -1335,7 +1335,7 @@ static int reiserfs_remount(struct superkfree (qf_names[i]);#endif err = -EINVAL ; - goto out_unlock; + goto out_err_unlock; }#ifdef CONFIG_QUOTA handle_quota_files (s, qf_names, &qfmt);@@ -1379,35 +1379,32 @@ static int reiserfs_remount(struct superif (blocks) { err =reiserfs_resize (s, blocks);if (err !=0 ) - goto out_unlock; + goto out_err_unlock; }if (*mount_flags &MS_RDONLY ) { +reiserfs_write_unlock (s);reiserfs_xattr_init (s, *mount_flags);/* remount read-only */ if (s->s_flags &MS_RDONLY )/* it is read-only already */ - goto out_ok; + goto out_ok_unlocked; -/* -* Drop write lock. Quota will retake it when needed and lock -* ordering requires calling dquot_suspend() without it. -*/ -reiserfs_write_unlock (s); err =dquot_suspend (s,-1 );if (err <0 ) goto out_err; -reiserfs_write_lock (s);/* try to remount file system with read-only permissions */ if (sb_umount_state (rs) ==REISERFS_VALID_FS ||REISERFS_SB (s)->s_mount_state !=REISERFS_VALID_FS ) { - goto out_ok; + goto out_ok_unlocked; } +reiserfs_write_lock (s); + err =journal_begin (&th, s,10 );if (err) - goto out_unlock; + goto out_err_unlock;/* Mounting a rw partition read-only. */ reiserfs_prepare_for_journal (s,SB_BUFFER_WITH_SB (s),1 );@@ -1416,13 +1413,14 @@ static int reiserfs_remount(struct super }else {/* remount read-write */ if (!(s->s_flags &MS_RDONLY )) { +reiserfs_write_unlock (s);reiserfs_xattr_init (s, *mount_flags); - goto out_ok;/* We are read-write already */ + goto out_ok_unlocked;/* We are read-write already */ }if (reiserfs_is_journal_aborted (journal)) { err = journal->j_errno; - goto out_unlock; + goto out_err_unlock; }handle_data_mode (s, mount_options);@@ -1431,7 +1429,7 @@ static int reiserfs_remount(struct super s->s_flags &= ~MS_RDONLY ;/* now it is safe to call journal_begin */ err =journal_begin (&th, s,10 );if (err) - goto out_unlock; + goto out_err_unlock;/* Mount a partition which is read-only, read-write */ reiserfs_prepare_for_journal (s,SB_BUFFER_WITH_SB (s),1 );@@ -1448,26 +1446,22 @@ static int reiserfs_remount(struct superSB_JOURNAL (s)->j_must_wait =1 ; err =journal_end (&th, s,10 );if (err) - goto out_unlock; + goto out_err_unlock; +reiserfs_write_unlock (s);if (!(*mount_flags &MS_RDONLY )) { -/* -* Drop write lock. Quota will retake it when needed and lock -* ordering requires calling dquot_resume() without it. -*/ -reiserfs_write_unlock (s);dquot_resume (s,-1 );reiserfs_write_lock (s);finish_unfinished (s); +reiserfs_write_unlock (s);reiserfs_xattr_init (s, *mount_flags); } -out_ok: +out_ok_unlocked:replace_mount_options (s, new_opts); -reiserfs_write_unlock (s);return 0 ; -out_unlock: +out_err_unlock:reiserfs_write_unlock (s); out_err:kfree (new_opts);@@ -2014,12 +2008,14 @@ static int reiserfs_fill_super(struct su goto error; } +reiserfs_write_unlock (s);if ((errval =reiserfs_lookup_privroot (s)) || (errval =reiserfs_xattr_init (s, s->s_flags))) {dput (s->s_root); s->s_root =NULL ; - goto error; + goto error_unlocked; } +reiserfs_write_lock (s);/* look for files which were to be removed in previous session */ finish_unfinished (s);@@ -2028,12 +2024,14 @@ static int reiserfs_fill_super(struct sureiserfs_info (s,"using 3.5.x disk format\n" ); } +reiserfs_write_unlock (s);if ((errval =reiserfs_lookup_privroot (s)) || (errval =reiserfs_xattr_init (s, s->s_flags))) {dput (s->s_root); s->s_root =NULL ; - goto error; + goto error_unlocked; } +reiserfs_write_lock (s); }// mark hash in super block: it could be unset. overwrite should be ok set_sb_hash_function_code (rs,function2code (sbi->s_hash_function));fs/reiserfs/xattr.c +17
-29@@ -81,8 +81,7 @@ static int xattr_unlink(struct inode *diint error;BUG_ON (!mutex_is_locked (&dir->i_mutex)); -reiserfs_mutex_lock_nested_safe (&dentry->d_inode->i_mutex, -I_MUTEX_CHILD , dir->i_sb); +mutex_lock_nested (&dentry->d_inode->i_mutex,I_MUTEX_CHILD ); error = dir->i_op->unlink (dir, dentry);mutex_unlock (&dentry->d_inode->i_mutex);@@ -96,8 +95,7 @@ static int xattr_rmdir(struct inode *dirint error;BUG_ON (!mutex_is_locked (&dir->i_mutex)); -reiserfs_mutex_lock_nested_safe (&dentry->d_inode->i_mutex, -I_MUTEX_CHILD , dir->i_sb); +mutex_lock_nested (&dentry->d_inode->i_mutex,I_MUTEX_CHILD ); error = dir->i_op->rmdir (dir, dentry);if (!error) dentry->d_inode->i_flags |=S_DEAD ;@@ -232,22 +230,17 @@ static int reiserfs_for_each_xattr(strucif (IS_PRIVATE (inode) ||get_inode_sd_version (inode) ==STAT_DATA_V1 )return 0 ; -reiserfs_write_unlock (inode->i_sb); dir =open_xa_dir (inode,XATTR_REPLACE );if (IS_ERR (dir)) { err =PTR_ERR (dir); -reiserfs_write_lock (inode->i_sb); goto out; }else if (!dir->d_inode) { err =0 ; -reiserfs_write_lock (inode->i_sb); goto out_dir; }mutex_lock_nested (&dir->d_inode->i_mutex,I_MUTEX_XATTR ); -reiserfs_write_lock (inode->i_sb); - buf.xadir = dir;while (1 ) { err =reiserfs_readdir_inode (dir->d_inode, &buf.ctx);@@ -281,14 +274,17 @@ static int reiserfs_for_each_xattr(strucint blocks =JOURNAL_PER_BALANCE_CNT *2 +2 +4 *REISERFS_QUOTA_TRANS_BLOCKS (inode->i_sb);struct reiserfs_transaction_handle th; +reiserfs_write_lock (inode->i_sb); err =journal_begin (&th, inode->i_sb, blocks); +reiserfs_write_unlock (inode->i_sb);if (!err) {int jerror; -reiserfs_mutex_lock_nested_safe ( - &dir->d_parent->d_inode->i_mutex, -I_MUTEX_XATTR , inode->i_sb); +mutex_lock_nested (&dir->d_parent->d_inode->i_mutex, +I_MUTEX_XATTR ); err =action (dir, data); +reiserfs_write_lock (inode->i_sb); jerror =journal_end (&th, inode->i_sb, blocks); +reiserfs_write_unlock (inode->i_sb);mutex_unlock (&dir->d_parent->d_inode->i_mutex); err = jerror ?: err; }@@ -455,9 +451,7 @@ static int lookup_and_delete_xattr(struc }if (dentry->d_inode) { -reiserfs_write_lock (inode->i_sb); err =xattr_unlink (xadir->d_inode, dentry); -reiserfs_write_unlock (inode->i_sb);update_ctime (inode); }@@ -491,24 +485,17 @@ reiserfs_xattr_set_handle(struct reiserfif (get_inode_sd_version (inode) ==STAT_DATA_V1 )return -EOPNOTSUPP ; -reiserfs_write_unlock (inode->i_sb); -if (!buffer) { err =lookup_and_delete_xattr (inode, name); -reiserfs_write_lock (inode->i_sb);return err; } dentry =xattr_lookup (inode, name, flags); -if (IS_ERR (dentry)) { -reiserfs_write_lock (inode->i_sb); +if (IS_ERR (dentry))return PTR_ERR (dentry); - }down_write (&REISERFS_I (inode)->i_xattr_sem); -reiserfs_write_lock (inode->i_sb); - xahash =xattr_hash (buffer, buffer_size);while (buffer_pos < buffer_size || buffer_pos ==0 ) {size_t chunk;@@ -538,6 +525,7 @@ reiserfs_xattr_set_handle(struct reiserf rxh->h_hash =cpu_to_le32 (xahash); } +reiserfs_write_lock (inode->i_sb); err =__reiserfs_write_begin (page, page_offset, chunk + skip);if (!err) {if (buffer)@@ -546,6 +534,7 @@ reiserfs_xattr_set_handle(struct reiserf page_offset + chunk + skip); } +reiserfs_write_unlock (inode->i_sb);unlock_page (page);reiserfs_put_page (page); buffer_pos += chunk;@@ -563,10 +552,8 @@ reiserfs_xattr_set_handle(struct reiserf .ia_valid = ATTR_SIZE | ATTR_CTIME, }; -reiserfs_write_unlock (inode->i_sb);mutex_lock_nested (&dentry->d_inode->i_mutex,I_MUTEX_XATTR );inode_dio_wait (dentry->d_inode); -reiserfs_write_lock (inode->i_sb); err =reiserfs_setattr (dentry, &newattrs);mutex_unlock (&dentry->d_inode->i_mutex);@@ -592,18 +579,19 @@ int reiserfs_xattr_set(struct inode *inoreiserfs_write_lock (inode->i_sb); error =journal_begin (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock (inode->i_sb);if (error) { -reiserfs_write_unlock (inode->i_sb);return error; } error =reiserfs_xattr_set_handle (&th, inode, name, buffer, buffer_size, flags); +reiserfs_write_lock (inode->i_sb); error2 =journal_end (&th, inode->i_sb, jbegin_count); +reiserfs_write_unlock (inode->i_sb);if (error ==0 ) error = error2; -reiserfs_write_unlock (inode->i_sb);return error; }@@ -968,7 +956,7 @@ int reiserfs_lookup_privroot(struct supeint err =0 ;/* If we don't have the privroot located yet - go find it */ -reiserfs_mutex_lock_safe (&s->s_root->d_inode->i_mutex, s); +mutex_lock (&s->s_root->d_inode->i_mutex); dentry =lookup_one_len (PRIVROOT_NAME , s->s_root,strlen (PRIVROOT_NAME ));if (!IS_ERR (dentry)) {@@ -996,14 +984,14 @@ int reiserfs_xattr_init(struct super_blo goto error;if (!privroot->d_inode && !(mount_flags &MS_RDONLY )) { -reiserfs_mutex_lock_safe (&s->s_root->d_inode->i_mutex, s); +mutex_lock (&s->s_root->d_inode->i_mutex); err =create_privroot (REISERFS_SB (s)->priv_root);mutex_unlock (&s->s_root->d_inode->i_mutex); }if (privroot->d_inode) { s->s_xattr = reiserfs_xattr_handlers; -reiserfs_mutex_lock_safe (&privroot->d_inode->i_mutex, s); +mutex_lock (&privroot->d_inode->i_mutex);if (!REISERFS_SB (s)->xattr_root) {struct dentry *dentry; dentry = lookup_one_len(XAROOT_NAME, privroot,fs/reiserfs/xattr_acl.c +10
-7@@ -49,13 +49,15 @@ posix_acl_set(struct dentry *dentry, conreiserfs_write_lock (inode->i_sb); error =journal_begin (&th, inode->i_sb, jcreate_blocks); +reiserfs_write_unlock (inode->i_sb);if (error ==0 ) { error =reiserfs_set_acl (&th, inode, type, acl); +reiserfs_write_lock (inode->i_sb); error2 =journal_end (&th, inode->i_sb, jcreate_blocks); +reiserfs_write_unlock (inode->i_sb);if (error2) error = error2; } -reiserfs_write_unlock (inode->i_sb); release_and_out:posix_acl_release (acl);@@ -435,12 +437,14 @@ int reiserfs_cache_default_acl(struct inreturn nblocks; } +/* +* Called under i_mutex +*/ int reiserfs_acl_chmod (struct inode *inode) {struct reiserfs_transaction_handle th;struct posix_acl *acl;size_t size; -int depth;int error;if (IS_PRIVATE (inode))@@ -454,9 +458,7 @@ int reiserfs_acl_chmod(struct inode *inoreturn 0 ; } -reiserfs_write_unlock (inode->i_sb); acl =reiserfs_get_acl (inode,ACL_TYPE_ACCESS ); -reiserfs_write_lock (inode->i_sb);if (!acl)return 0 ;if (IS_ERR (acl))@@ -466,16 +468,18 @@ int reiserfs_acl_chmod(struct inode *inoreturn error; size =reiserfs_xattr_nblocks (inode,reiserfs_acl_size (acl->a_count)); - depth =reiserfs_write_lock_once (inode->i_sb); +reiserfs_write_lock (inode->i_sb); error =journal_begin (&th, inode->i_sb, size *2 ); +reiserfs_write_unlock (inode->i_sb);if (!error) {int error2; error =reiserfs_set_acl (&th, inode,ACL_TYPE_ACCESS , acl); +reiserfs_write_lock (inode->i_sb); error2 =journal_end (&th, inode->i_sb, size *2 ); +reiserfs_write_unlock (inode->i_sb);if (error2) error = error2; } -reiserfs_write_unlock_once (inode->i_sb, depth);posix_acl_release (acl);return error; } --To unsubscribe from this list: send the line "unsubscribe reiserfs-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Jeff Mahoney SUSE Labs
PATCH 2/3 reiserfs: locking, handle nested locks properly
In reply to [email protected]The reiserfs write lock replaced the BKL and uses similar semantics.
Frederic's locking code makes a distinction between when the lock is nested and when it's being acquired/released, but I don't think that's the right distinction to make.
The right distinction is between the lock being released at end-of-use and the lock being released for a schedule. The unlock should return the depth and the lock should restore it, rather than the other way around as it is now.
This patch implements that and adds a number of places where the lock should be dropped.
---
fs/reiserfs/bitmap.c | 5 +- fs/reiserfs/dir.c | 7 +-- fs/reiserfs/fix_node.c | 26 ++++++------ fs/reiserfs/inode.c | 77 ++++++++++++++++-------------------- fs/reiserfs/ioctl.c | 7 +-- fs/reiserfs/journal.c | 104 ++++++++++++++++++++++++++----------------------- fs/reiserfs/lock.c | 66 +++++++++++++++++++++---------- fs/reiserfs/namei.c | 24 +++-------- fs/reiserfs/prints.c | 5 +- fs/reiserfs/reiserfs.h | 82 +++++++++++++++++++++++--------------- fs/reiserfs/resize.c | 10 +++- fs/reiserfs/stree.c | 24 +++++++---- fs/reiserfs/super.c | 5 -- 13 files changed, 248 insertions(+), 194 deletions(-)
fs/reiserfs/bitmap.c +3 -2
@@ -1340,10 +1340,11 @@ struct buffer_head *reiserfs_read_bitmap "reading failed", __func__, block); else {if (buffer_locked (bh)) { +int depth;PROC_INFO_INC (sb, scan_bitmap.wait); -reiserfs_write_unlock (sb); + depth =reiserfs_write_unlock_nested (sb);__wait_on_buffer (bh); -reiserfs_write_lock (sb); +reiserfs_write_lock_nested (sb, depth); }BUG_ON (!buffer_uptodate (bh));BUG_ON (atomic_read (&bh->b_count) ==0 );
fs/reiserfs/dir.c +4 -3
@@ -71,6 +71,7 @@ int reiserfs_readdir_inode(struct inodechar small_buf[32 ];/* avoid kmalloc if we can */ struct reiserfs_dir_entry de;int ret =0 ; +int depth;reiserfs_write_lock (inode->i_sb);
@@ -181,17 +182,17 @@ int reiserfs_readdir_inode(struct inode* Since filldir might sleep, we can release * the write lock here for other waiters */ -reiserfs_write_unlock (inode->i_sb); + depth =reiserfs_write_unlock_nested (inode->i_sb);if (!dir_emit (ctx, local_buf, d_reclen, d_ino,DT_UNKNOWN )) { -reiserfs_write_lock (inode->i_sb); +reiserfs_write_lock_nested (inode->i_sb, depth);if (local_buf != small_buf) {kfree (local_buf); } goto end; } -reiserfs_write_lock (inode->i_sb); +reiserfs_write_lock_nested (inode->i_sb, depth);if (local_buf != small_buf) {kfree (local_buf); }
fs/reiserfs/fix_node.c +14 -12
@@ -1022,9 +1022,9 @@ static int get_far_parent(struct tree_baif (buffer_locked (*pcom_father)) {/* Release the write lock while the buffer is busy */ -reiserfs_write_unlock (tb->tb_sb); +int depth =reiserfs_write_unlock_nested (tb->tb_sb);__wait_on_buffer (*pcom_father); -reiserfs_write_lock (tb->tb_sb); +reiserfs_write_lock_nested (tb->tb_sb, depth);if (FILESYSTEM_CHANGED_TB (tb)) {brelse (*pcom_father);return REPEAT_SEARCH ;
@@ -1929,9 +1929,9 @@ static int get_direct_parent(struct treereturn REPEAT_SEARCH ;if (buffer_locked (bh)) { -reiserfs_write_unlock (tb->tb_sb); +int depth =reiserfs_write_unlock_nested (tb->tb_sb);__wait_on_buffer (bh); -reiserfs_write_lock (tb->tb_sb); +reiserfs_write_lock_nested (tb->tb_sb, depth);if (FILESYSTEM_CHANGED_TB (tb))return REPEAT_SEARCH ; }
@@ -1952,6 +1952,7 @@ static int get_neighbors(struct tree_balunsigned long son_number;struct super_block *sb = tb->tb_sb;struct buffer_head *bh; +int depth;PROC_INFO_INC (sb, get_neighbors[h]);
@@ -1969,9 +1970,9 @@ static int get_neighbors(struct tree_bal tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> FL[h]); son_number =B_N_CHILD_NUM (tb->FL[h], child_position); -reiserfs_write_unlock (sb); + depth =reiserfs_write_unlock_nested (tb->tb_sb); bh =sb_bread (sb, son_number); -reiserfs_write_lock (sb); +reiserfs_write_lock_nested (tb->tb_sb, depth);if (!bh)return IO_ERROR ;if (FILESYSTEM_CHANGED_TB (tb)) {
@@ -2009,9 +2010,9 @@ static int get_neighbors(struct tree_bal child_position = (bh == tb->FR[h]) ? tb->rkey[h] +1 :0 ; son_number =B_N_CHILD_NUM (tb->FR[h], child_position); -reiserfs_write_unlock (sb); + depth =reiserfs_write_unlock_nested (tb->tb_sb); bh =sb_bread (sb, son_number); -reiserfs_write_lock (sb); +reiserfs_write_lock_nested (tb->tb_sb, depth);if (!bh)return IO_ERROR ;if (FILESYSTEM_CHANGED_TB (tb)) {
@@ -2272,6 +2273,7 @@ static int wait_tb_buffers_until_unlocke }if (locked) { +int depth;#ifdef CONFIG_REISERFS_CHECK repeat_counter++;if ((repeat_counter %10000 ) ==0 ) {
@@ -2286,9 +2288,9 @@ static int wait_tb_buffers_until_unlocke REPEAT_SEARCH : CARRY_ON; }#endif -reiserfs_write_unlock (tb->tb_sb); + depth =reiserfs_write_unlock_nested (tb->tb_sb);__wait_on_buffer (locked); -reiserfs_write_lock (tb->tb_sb); +reiserfs_write_lock_nested (tb->tb_sb, depth);if (FILESYSTEM_CHANGED_TB (tb))return REPEAT_SEARCH ; }
@@ -2359,9 +2361,9 @@ int fix_nodes(int op_mode, struct tree_b/* if it possible in indirect_to_direct conversion */ if (buffer_locked (tbS0)) { -reiserfs_write_unlock (tb->tb_sb); +int depth =reiserfs_write_unlock_nested (tb->tb_sb);__wait_on_buffer (tbS0); -reiserfs_write_lock (tb->tb_sb); +reiserfs_write_lock_nested (tb->tb_sb, depth);if (FILESYSTEM_CHANGED_TB (tb))return REPEAT_SEARCH ; }
fs/reiserfs/inode.c +36 -41
270 lines not on this page · raw message
fs/reiserfs/ioctl.c +3 -4
@@ -167,7 +167,6 @@ int reiserfs_commit_write(struct file *fint reiserfs_unpack (struct inode *inode,struct file *filp) {int retval =0 ; -int depth;int index;struct page *page;struct address_space *mapping;
@@ -183,11 +182,11 @@ int reiserfs_unpack(struct inode *inode,return 0 ; } - depth =reiserfs_write_lock_once (inode->i_sb); -/* we need to make sure nobody is changing the file size beneath us */ reiserfs_mutex_lock_safe (&inode->i_mutex, inode->i_sb); +reiserfs_write_lock (inode->i_sb); + write_from = inode->i_size & (blocksize -1 );/* if we are on a block boundary, we are already unpacked. */ if (write_from ==0 ) {
@@ -221,6 +220,6 @@ int reiserfs_unpack(struct inode *inode, out:mutex_unlock (&inode->i_mutex); -reiserfs_write_unlock_once (inode->i_sb, depth); +reiserfs_write_unlock (inode->i_sb);return retval; }
fs/reiserfs/journal.c +56 -48
298 lines not on this page · raw message
fs/reiserfs/lock.c +45 -21
96 lines not on this page · raw message
fs/reiserfs/namei.c +8 -16
@@ -325,7 +325,6 @@ static struct dentry *reiserfs_lookup(st unsigned int flags) {int retval; -int lock_depth;struct inode *inode =NULL ;struct reiserfs_dir_entry de;INITIALIZE_PATH (path_to_entry);
@@ -333,12 +332,7 @@ static struct dentry *reiserfs_lookup(stif (REISERFS_MAX_NAME (dir->i_sb->s_blocksize) < dentry->d_name.len)return ERR_PTR (-ENAMETOOLONG ); -/* -* Might be called with or without the write lock, must be careful -* to not recursively hold it in case we want to release the lock -* before rescheduling. -*/ - lock_depth =reiserfs_write_lock_once (dir->i_sb); +reiserfs_write_lock (dir->i_sb); de.de_gen_number_bit_string =NULL ; retval =
@@ -349,7 +343,7 @@ static struct dentry *reiserfs_lookup(st inode =reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id));if (!inode ||IS_ERR (inode)) { -reiserfs_write_unlock_once (dir->i_sb, lock_depth); +reiserfs_write_unlock (dir->i_sb);return ERR_PTR (-EACCES ); }
@@ -358,7 +352,7 @@ static struct dentry *reiserfs_lookup(stif (IS_PRIVATE (dir)) inode->i_flags |=S_PRIVATE ; } -reiserfs_write_unlock_once (dir->i_sb, lock_depth); +reiserfs_write_unlock (dir->i_sb);if (retval ==IO_ERROR ) {return ERR_PTR (-EIO ); }
@@ -727,7 +721,6 @@ static int reiserfs_mkdir(struct inode *struct inode *inode;struct reiserfs_transaction_handle th;struct reiserfs_security_handle security; -int lock_depth;/* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 +
@@ -753,7 +746,7 @@ static int reiserfs_mkdir(struct inode *return retval; } jbegin_count += retval; - lock_depth =reiserfs_write_lock_once (dir->i_sb); +reiserfs_write_lock (dir->i_sb); retval =journal_begin (&th, dir->i_sb, jbegin_count);if (retval) {
@@ -804,7 +797,7 @@ static int reiserfs_mkdir(struct inode *d_instantiate (dentry, inode); retval =journal_end (&th, dir->i_sb, jbegin_count); out_failed: -reiserfs_write_unlock_once (dir->i_sb, lock_depth); +reiserfs_write_unlock (dir->i_sb);return retval; }
@@ -920,7 +913,6 @@ static int reiserfs_unlink(struct inodestruct reiserfs_transaction_handle th;int jbegin_count;unsigned long savelink; -int depth;dquot_initialize (dir);
@@ -934,7 +926,7 @@ static int reiserfs_unlink(struct inodeJOURNAL_PER_BALANCE_CNT *2 +2 +4 *REISERFS_QUOTA_TRANS_BLOCKS (dir->i_sb); - depth =reiserfs_write_lock_once (dir->i_sb); +reiserfs_write_lock (dir->i_sb); retval =journal_begin (&th, dir->i_sb, jbegin_count);if (retval) goto out_unlink;
@@ -995,7 +987,7 @@ static int reiserfs_unlink(struct inode retval =journal_end (&th, dir->i_sb, jbegin_count);reiserfs_check_path (&path); -reiserfs_write_unlock_once (dir->i_sb, depth); +reiserfs_write_unlock (dir->i_sb);return retval; end_unlink:
@@ -1005,7 +997,7 @@ static int reiserfs_unlink(struct inodeif (err) retval = err; out_unlink: -reiserfs_write_unlock_once (dir->i_sb, depth); +reiserfs_write_unlock (dir->i_sb);return retval; }
fs/reiserfs/prints.c +3 -2
@@ -358,12 +358,13 @@ void __reiserfs_panic(struct super_blockdump_stack ();#endif if (sb) -panic (KERN_WARNING "REISERFS panic (device %s): %s%s%s: %s\n" , +printk (KERN_WARNING "REISERFS panic (device %s): %s%s%s: %s\n" , sb->s_id, id ? id :"" , id ?" " :"" , function, error_buf);else -panic (KERN_WARNING "REISERFS panic: %s%s%s: %s\n" , +printk (KERN_WARNING "REISERFS panic: %s%s%s: %s\n" , id ? id :"" , id ?" " :"" , function, error_buf); +BUG (); } void __reiserfs_error(struct super_block *sb, const char *id,
fs/reiserfs/reiserfs.h +50 -32
109 lines not on this page · raw message
fs/reiserfs/resize.c +8 -2
@@ -34,6 +34,7 @@ int reiserfs_resize(struct super_block *unsigned long int block_count, free_blocks;int i;int copy_size; +int depth; sb =SB_DISK_SUPER_BLOCK (s);
@@ -43,7 +44,9 @@ int reiserfs_resize(struct super_block * }/* check the device size */ + depth =reiserfs_write_unlock_nested (s); bh =sb_bread (s, block_count_new -1 ); +reiserfs_write_lock_nested (s, depth);if (!bh) {printk ("reiserfs_resize: can\'t read last block\n" );return -EINVAL ;
@@ -125,9 +128,12 @@ int reiserfs_resize(struct super_block ** transaction begins, and the new bitmaps don't matter if the * transaction fails. */ for (i = bmap_nr; i < bmap_nr_new; i++) { +int depth;/* don't use read_bitmap_block since it will cache * the uninitialized bitmap */ + depth =reiserfs_write_unlock_nested (s); bh =sb_bread (s, i * s->s_blocksize *8 ); +reiserfs_write_lock_nested (s, depth);if (!bh) {vfree (bitmap);return -EIO ;
@@ -138,9 +144,9 @@ int reiserfs_resize(struct super_block *set_buffer_uptodate (bh);mark_buffer_dirty (bh); -reiserfs_write_unlock (s); + depth =reiserfs_write_unlock_nested (s);sync_dirty_buffer (bh); -reiserfs_write_lock (s); +reiserfs_write_lock_nested (s, depth);// update bitmap_info stuff bitmap[i].free_count =sb_blocksize (sb) *8 -1 ;brelse (bh);
fs/reiserfs/stree.c +16 -8
@@ -550,7 +550,8 @@ static bool search_by_key_reada(struct s*/ if (!buffer_uptodate (bh[j])) {if (!unlocked) { -reiserfs_write_unlock (s); +int depth =-1 ;/* avoiding __must_check */ + depth =reiserfs_write_unlock_nested (s); unlocked = true; }ll_rw_block (READA ,1 , bh + j);
@@ -625,7 +626,7 @@ int search_by_key(struct super_block *sb block_number =SB_ROOT_BLOCK (sb); expected_level =-1 ;while (1 ) { - +int depth;#ifdef CONFIG_REISERFS_CHECK if (!(++repeat_counter %50000 )) reiserfs_warning(sb, "PAP-5100",
@@ -646,25 +647,29 @@ int search_by_key(struct super_block *sbif ((bh = last_element->pe_buffer =sb_getblk (sb, block_number))) {bool unlocked = false; - + depth =REISERFS_SB (sb)->lock_depth;if (!buffer_uptodate (bh) && reada_count >1 )/* may unlock the write lock */ unlocked =search_by_key_reada (sb, reada_bh, reada_blocks, reada_count); +/* * If we haven't already unlocked the write lock, * then we need to do that here before reading * the current block */ if (!buffer_uptodate (bh) && !unlocked) { -reiserfs_write_unlock (sb); + depth =reiserfs_write_unlock_nested (sb); + unlocked = true; + }else if (!unlocked) {/* debug */ + depth =reiserfs_write_unlock_nested (sb); unlocked = true; }ll_rw_block (READ ,1 , &bh);wait_on_buffer (bh);if (unlocked) -reiserfs_write_lock (sb); +reiserfs_write_lock_nested (sb, depth);if (!buffer_uptodate (bh)) goto io_error; }else {
@@ -991,6 +996,7 @@ static char prepare_for_delete_or_cut(ststruct super_block *sb = inode->i_sb;struct item_head *p_le_ih =PATH_PITEM_HEAD (path);struct buffer_head *bh =PATH_PLAST_BUFFER (path); +int depth;BUG_ON (!th->t_trans_id);
@@ -1059,9 +1065,11 @@ static char prepare_for_delete_or_cut(streiserfs_free_block (th, inode, block,1 ); } -reiserfs_write_unlock (sb); -cond_resched (); -reiserfs_write_lock (sb); +if (need_resched ()) { + depth =reiserfs_write_unlock_nested (sb); +cond_resched (); +reiserfs_write_lock_nested (sb, depth); + }if (item_moved (&s_ih, path)) { need_re_search =1 ;
fs/reiserfs/super.c +2 -3
@@ -624,7 +624,6 @@ static void reiserfs_dirty_inode(structstruct reiserfs_transaction_handle th;int err =0 ; -int lock_depth;if (inode->i_sb->s_flags &MS_RDONLY ) { reiserfs_warning(inode->i_sb, "clm-6006",
@@ -632,7 +631,7 @@ static void reiserfs_dirty_inode(struct inode->i_ino);return ; } - lock_depth =reiserfs_write_lock_once (inode->i_sb); +reiserfs_write_lock (inode->i_sb);/* this is really only used for atime updates, so they don't have ** to be included in O_SYNC or fsync
@@ -645,7 +644,7 @@ static void reiserfs_dirty_inode(structjournal_end (&th, inode->i_sb,1 ); out: -reiserfs_write_unlock_once (inode->i_sb, lock_depth); +reiserfs_write_unlock (inode->i_sb); }static int reiserfs_show_options (struct seq_file *seq,struct dentry *root)
PATCH 3/3 reiserfs: locking, release lock around quota operations
In reply to [email protected]Previous commits released the write lock across quota operations but missed several places. In particular, the free operations can also call into the file system code and take the write lock, causing deadlocks.
This patch introduces some more helpers and uses them for quota call sites. Without this patch applied, reiserfs + quotas runs into deadlocks under anything more than trivial load.
With this patch applied, reiserfs survives a 50-thread stress test with quotas enabled and a default ACL set. Without it, it deadlocks fairly quickly under the same load.
---
fs/reiserfs/bitmap.c | 26 +++++++++++++++++++------- fs/reiserfs/inode.c | 28 ++++++++++++++++++++-------- fs/reiserfs/lock.c | 7 +++++++ fs/reiserfs/namei.c | 24 ++++++++++++++---------- fs/reiserfs/reiserfs.h | 44 ++++++++++---------------------------------- fs/reiserfs/stree.c | 28 +++++++++++++++++++++++----- fs/reiserfs/super.c | 42 ++++++++++++++++++++++++++---------------- 7 files changed, 119 insertions(+), 80 deletions(-)
fs/reiserfs/bitmap.c +19 -7
@@ -423,8 +423,11 @@ static void _reiserfs_free_block(structset_sb_free_blocks (rs,sb_free_blocks (rs) +1 );journal_mark_dirty (th, s, sbh); -if (for_unformatted) +if (for_unformatted) { +int depth =reiserfs_write_unlock_nested (s);dquot_free_block_nodirty (inode,1 ); +reiserfs_write_lock_nested (s, depth); + } } void reiserfs_free_block(struct reiserfs_transaction_handle *th,
@@ -1128,6 +1131,7 @@ static inline int blocknrs_and_prealloc_b_blocknr_t finish =SB_BLOCK_COUNT (s) -1 ;int passno =0 ;int nr_allocated =0 ; +int depth;determine_prealloc_size (hint);if (!hint->formatted_node) {
@@ -1137,10 +1141,13 @@ static inline int blocknrs_and_prealloc_"reiserquota: allocating %d blocks id=%u" , amount_needed, hint->inode->i_uid);#endif + depth =reiserfs_write_unlock_nested (s); quota_ret =dquot_alloc_block_nodirty (hint->inode, amount_needed); -if (quota_ret)/* Quota exceeded? */ +if (quota_ret) {/* Quota exceeded? */ +reiserfs_write_lock_nested (s, depth);return QUOTA_EXCEEDED ; + }if (hint->preallocate && hint->prealloc_size) {#ifdef REISERQUOTA_DEBUG reiserfs_debug(s, REISERFS_DEBUG_CODE,
@@ -1153,6 +1160,7 @@ static inline int blocknrs_and_prealloc_ hint->preallocate = hint->prealloc_size =0 ; }/* for unformatted nodes, force large allocations */ +reiserfs_write_lock_nested (s, depth); } do {
@@ -1181,9 +1189,12 @@ static inline int blocknrs_and_prealloc_ hint->inode->i_uid);#endif /* Free not allocated blocks */ -dquot_free_block_nodirty (hint->inode, + depth =reiserfs_write_unlock_nested (s); +dquot_free_block_nodirty ( + hint->inode, amount_needed + hint->prealloc_size - nr_allocated); +reiserfs_write_lock_nested (s, depth); }while (nr_allocated--) reiserfs_free_block(hint->th, hint->inode,
@@ -1214,10 +1225,11 @@ static inline int blocknrs_and_prealloc_REISERFS_I (hint->inode)->i_prealloc_count, hint->inode->i_uid);#endif -dquot_free_block_nodirty (hint->inode, amount_needed + - hint->prealloc_size - nr_allocated - -REISERFS_I (hint->inode)-> - i_prealloc_count); + depth =reiserfs_write_unlock_nested (s); +dquot_free_block_nodirty (hint->inode, + amount_needed + hint->prealloc_size - nr_allocated - +REISERFS_I (hint->inode)->i_prealloc_count); +reiserfs_write_lock_nested (s, depth); }return CARRY_ON ;
fs/reiserfs/inode.c +20 -8
@@ -25,6 +25,7 @@ int reiserfs_commit_write(struct file *fvoid reiserfs_evict_inode (struct inode *inode) { +struct super_block *sb = inode->i_sb;/* We need blocks for transaction + (user+group) quota update (possibly delete) */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 +
@@ -57,8 +58,11 @@ void reiserfs_evict_inode(struct inode */* Do quota update inside a transaction for journaled quotas. We must do that * after delete_object so that quota updates go into the same transaction as * stat data deletion */ -if (!err) +if (!err) { +int depth =reiserfs_write_unlock_nested (sb);dquot_free_inode (inode); +reiserfs_write_lock_nested (sb, depth); + }if (journal_end (&th, inode->i_sb, jbegin_count)) goto out;
@@ -1523,7 +1527,10 @@ struct inode *reiserfs_iget(struct superif (comp_short_keys (INODE_PKEY (inode), key) ||is_bad_inode (inode)) {/* either due to i/o error or a stale NFS handle */ +int depth; + depth =reiserfs_write_unlock_nested (s);iput (inode); +reiserfs_write_lock_nested (s, depth); inode =NULL ; }return inode;
@@ -1540,12 +1547,12 @@ static struct dentry *reiserfs_get_dentr key.on_disk_key.k_dir_id = dir_id;reiserfs_write_lock (sb); inode =reiserfs_iget (sb, &key); +reiserfs_write_unlock (sb);if (inode && !IS_ERR (inode) && generation !=0 && generation != inode->i_generation) {iput (inode); inode =NULL ; } -reiserfs_write_unlock (sb);return d_obtain_alias (inode); }
@@ -1778,11 +1785,13 @@ int reiserfs_new_inode(struct reiserfs_tint err;int depth; +reiserfs_check_lock_nested (dir->i_sb, __func__); +BUG_ON (!th->t_trans_id); -reiserfs_write_unlock (inode->i_sb); + depth =reiserfs_write_unlock_nested (dir->i_sb); err =dquot_alloc_inode (inode); -reiserfs_write_lock (inode->i_sb); +reiserfs_write_lock_nested (dir->i_sb, depth);if (err) goto out_end_trans;if (!dir->i_nlink) {
@@ -1809,10 +1818,10 @@ int reiserfs_new_inode(struct reiserfs_tmemcpy (INODE_PKEY (inode), &(ih.ih_key),KEY_SIZE ); args.dirid =le32_to_cpu (ih.ih_key.k_dir_id); - depth =reiserfs_write_unlock_nested (inode->i_sb); +reiserfs_write_unlock (inode->i_sb); err =insert_inode_locked4 (inode, args.objectid, reiserfs_find_actor, &args); -reiserfs_write_lock_nested (inode->i_sb, depth); +reiserfs_write_lock (inode->i_sb);if (err) { err = -EINVAL ; goto out_bad_inode;
@@ -1983,14 +1992,16 @@ int reiserfs_new_inode(struct reiserfs_tINODE_PKEY (inode)->k_objectid =0 ;/* Quota change must be inside a transaction for journaling */ + depth =reiserfs_write_unlock_nested (inode->i_sb);dquot_free_inode (inode); +reiserfs_write_lock_nested (inode->i_sb, depth); out_end_trans:journal_end (th, th->t_super, th->t_blocks_allocated); -reiserfs_write_unlock (inode->i_sb);/* Drop can be outside and it needs more credits so it's better to have it outside */ + depth =reiserfs_write_unlock_nested (inode->i_sb);dquot_drop (inode); -reiserfs_write_lock (inode->i_sb); +reiserfs_write_lock_nested (inode->i_sb, depth); inode->i_flags |=S_NOQUOTA ;make_bad_inode (inode);
@@ -1998,6 +2009,7 @@ int reiserfs_new_inode(struct reiserfs_tclear_nlink (inode); th->t_trans_id =0 ;/* so the caller can't use this handle later */ unlock_new_inode (inode);/* OK to do even if we hadn't locked it */ +reiserfs_write_unlock (inode->i_sb);iput (inode);return err; }
fs/reiserfs/lock.c +7 -0
@@ -111,6 +111,13 @@ void reiserfs_check_lock_depth(struct suWARN_ON (sb_i->lock_depth <0 ); } +void reiserfs_check_lock_nested (struct super_block *sb,const char *caller) +{ +struct reiserfs_sb_info *sb_i =REISERFS_SB (sb); + +WARN_ON (sb_i->lock_depth >0 ); +} +#ifdef CONFIG_REISERFS_CHECK void reiserfs_lock_check_recursive (struct super_block *sb) {
fs/reiserfs/namei.c +14 -10
@@ -604,8 +604,9 @@ static int reiserfs_create(struct inode retval =reiserfs_new_inode (&th, dir, mode,NULL ,0 /*i_size */ , dentry, inode, &security); +/* inode is dropped and write lock is released */ if (retval) - goto out_failed; +return retval; inode->i_op = &reiserfs_file_inode_operations; inode->i_fop = &reiserfs_file_operations;
@@ -678,9 +679,9 @@ static int reiserfs_mknod(struct inode * retval =reiserfs_new_inode (&th, dir, mode,NULL ,0 /*i_size */ , dentry, inode, &security); -if (retval) { - goto out_failed; - } +/* inode is dropped and write lock is released */ +if (retval) +return retval; inode->i_op = &reiserfs_special_inode_operations;init_special_inode (inode, inode->i_mode, rdev);
@@ -763,9 +764,10 @@ static int reiserfs_mkdir(struct inode *old_format_only (dir->i_sb) ?EMPTY_DIR_SIZE_V1 :EMPTY_DIR_SIZE , dentry, inode, &security); +/* inode is dropped and write lock is released */ if (retval) {DEC_DIR_INODE_NLINK (dir) - goto out_failed; + return retval; }reiserfs_update_inode_transaction (inode);
@@ -787,8 +789,9 @@ static int reiserfs_mkdir(struct inode *if (err) retval = err;unlock_new_inode (inode); +reiserfs_write_unlock (dir->i_sb);iput (inode); - goto out_failed; +return retval; }// the above add_entry did not update dir's stat data reiserfs_update_sd (&th, dir);
@@ -1060,9 +1063,9 @@ static int reiserfs_symlink(struct inodereiserfs_new_inode (&th, parent_dir, mode, name,strlen (symname), dentry, inode, &security);kfree (name); -if (retval) {/* reiserfs_new_inode iputs for us */ - goto out_failed; - } +/* inode is dropped and write lock is released */ +if (retval) +return retval;reiserfs_update_inode_transaction (inode);reiserfs_update_inode_transaction (parent_dir);
@@ -1084,8 +1087,9 @@ static int reiserfs_symlink(struct inodeif (err) retval = err;unlock_new_inode (inode); +reiserfs_write_unlock (parent_dir->i_sb);iput (inode); - goto out_failed; +return retval; }unlock_new_inode (inode);
fs/reiserfs/reiserfs.h +10 -34
74 lines not on this page · raw message
fs/reiserfs/stree.c +23 -5
@@ -1198,6 +1198,7 @@ int reiserfs_delete_item(struct reiserfsstruct item_head *q_ih;int quota_cut_bytes;int ret_value, del_size, removed; +int depth;#ifdef CONFIG_REISERFS_CHECK char mode;
@@ -1307,7 +1308,9 @@ int reiserfs_delete_item(struct reiserfs"reiserquota delete_item(): freeing %u, id=%u type=%c" , quota_cut_bytes, inode->i_uid, head2type(&s_ih));#endif + depth =reiserfs_write_unlock_nested (sb);dquot_free_space_nodirty (inode, quota_cut_bytes); +reiserfs_write_lock_nested (sb, depth);/* Return deleted body length */ return ret_value;
@@ -1340,6 +1343,7 @@ void reiserfs_delete_solid_item(struct rstruct cpu_key cpu_key;int retval;int quota_cut_bytes =0 ; +struct super_block *sb = th->t_super;BUG_ON (!th->t_trans_id);
@@ -1385,14 +1389,17 @@ void reiserfs_delete_solid_item(struct rif (retval ==CARRY_ON ) {do_balance (&tb,NULL ,NULL ,M_DELETE );if (inode) {/* Should we count quota for item? (we don't count quotas for save-links) */ +int depth;#ifdef REISERQUOTA_DEBUG reiserfs_debug (th->t_super,REISERFS_DEBUG_CODE ,"reiserquota delete_solid_item(): freeing %u id=%u type=%c" , quota_cut_bytes, inode->i_uid,key2type (key));#endif + depth =reiserfs_write_unlock_nested (sb);dquot_free_space_nodirty (inode, quota_cut_bytes); +reiserfs_write_lock_nested (sb, depth); }break ; }
@@ -1569,6 +1576,7 @@ int reiserfs_cut_from_item(struct reiserint retval2 =-1 ;int quota_cut_bytes;loff_t tail_pos =0 ; +int depth;BUG_ON (!th->t_trans_id);
@@ -1741,7 +1749,9 @@ int reiserfs_cut_from_item(struct reiser"reiserquota cut_from_item(): freeing %u id=%u type=%c" , quota_cut_bytes, inode->i_uid, '?');#endif + depth =reiserfs_write_unlock_nested (sb);dquot_free_space_nodirty (inode, quota_cut_bytes); +reiserfs_write_lock_nested (sb, depth);return ret_value; }
@@ -1964,6 +1974,7 @@ int reiserfs_paste_into_item(struct reisstruct tree_balance s_paste_balance;int retval;int fs_gen; +int depth;BUG_ON (!th->t_trans_id);
@@ -1976,9 +1987,9 @@ int reiserfs_paste_into_item(struct reis key2type(&(key->on_disk_key)));#endif -reiserfs_write_unlock (inode->i_sb); + depth =reiserfs_write_unlock_nested (inode->i_sb); retval =dquot_alloc_space_nodirty (inode, pasted_size); -reiserfs_write_lock (inode->i_sb); +reiserfs_write_lock_nested (inode->i_sb, depth);if (retval) {pathrelse (search_path);return retval;
@@ -2035,7 +2046,9 @@ int reiserfs_paste_into_item(struct reis pasted_size, inode->i_uid, key2type(&(key->on_disk_key)));#endif + depth =reiserfs_write_unlock_nested (inode->i_sb);dquot_free_space_nodirty (inode, pasted_size); +reiserfs_write_lock_nested (inode->i_sb, depth);return retval; }
@@ -2050,10 +2063,12 @@ int reiserfs_insert_item(struct reiserfs struct item_head *ih, struct inode *inode, const char *body) { + struct super_block *sb = th->t_super;struct tree_balance s_ins_balance;int retval;int fs_gen =0 ;int quota_bytes =0 ; +int depth;BUG_ON (!th->t_trans_id);
@@ -2071,11 +2086,11 @@ int reiserfs_insert_item(struct reiserfs"reiserquota insert_item(): allocating %u id=%u type=%c" , quota_bytes, inode->i_uid, head2type(ih));#endif -reiserfs_write_unlock (inode->i_sb);/* We can't dirty inode here. It would be immediately written but * appropriate stat item isn't inserted yet... */ + depth =reiserfs_write_unlock_nested (sb); retval =dquot_alloc_space_nodirty (inode, quota_bytes); -reiserfs_write_lock (inode->i_sb); +reiserfs_write_lock_nested (sb, depth);if (retval) {pathrelse (path);return retval;
@@ -2126,7 +2141,10 @@ int reiserfs_insert_item(struct reiserfs"reiserquota insert_item(): freeing %u id=%u type=%c" , quota_bytes, inode->i_uid, head2type(ih));#endif -if (inode) +if (inode) { + depth =reiserfs_write_unlock_nested (sb);dquot_free_space_nodirty (inode, quota_bytes); +reiserfs_write_lock_nested (sb, depth); + }return retval; }
fs/reiserfs/super.c +26 -16
127 lines not on this page · raw message