aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2010-10-27 22:08:46 -0400
committerTheodore Ts'o <tytso@mit.edu>2010-10-27 22:08:46 -0400
commit3d287de3b828226e5a450c7fd5bf4283792dc2b0 (patch)
tree4adcc534e2042aed924750df3ef2433bd2f14fd8 /fs/ext4/inode.c
parentbeed5ecbaa377fa8bb6a54a6608e8725a21efdbc (diff)
ext4: optimize orphan_list handling for ext4_setattr
Surprisingly chown() on ext4 is not SMP scalable operation. Due to unconditional orphan_del(NULL, inode) in ext4_setattr() result in significant performance overhead because of global orphan mutex, especially in no-journal mode (where orphan_add() is noop). It is possible to skip explicit orphan_del if possible. Results of fchown() micro-benchmark in no-journal mode while (1) { iteration++; fchown(fd, uid, gid); fchown(fd, uid + 1, gid + 1) } measured: iterations per millisecond | nr_tasks | w/o patch | with patch | | 1 | 142 | 185 | | 4 | 109 | 642 | Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9e60d0b8fa75..3ba237b0b2aa 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -5281,6 +5281,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
5281{ 5281{
5282 struct inode *inode = dentry->d_inode; 5282 struct inode *inode = dentry->d_inode;
5283 int error, rc = 0; 5283 int error, rc = 0;
5284 int orphan = 0;
5284 const unsigned int ia_valid = attr->ia_valid; 5285 const unsigned int ia_valid = attr->ia_valid;
5285 5286
5286 error = inode_change_ok(inode, attr); 5287 error = inode_change_ok(inode, attr);
@@ -5336,8 +5337,10 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
5336 error = PTR_ERR(handle); 5337 error = PTR_ERR(handle);
5337 goto err_out; 5338 goto err_out;
5338 } 5339 }
5339 5340 if (ext4_handle_valid(handle)) {
5340 error = ext4_orphan_add(handle, inode); 5341 error = ext4_orphan_add(handle, inode);
5342 orphan = 1;
5343 }
5341 EXT4_I(inode)->i_disksize = attr->ia_size; 5344 EXT4_I(inode)->i_disksize = attr->ia_size;
5342 rc = ext4_mark_inode_dirty(handle, inode); 5345 rc = ext4_mark_inode_dirty(handle, inode);
5343 if (!error) 5346 if (!error)
@@ -5355,6 +5358,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
5355 goto err_out; 5358 goto err_out;
5356 } 5359 }
5357 ext4_orphan_del(handle, inode); 5360 ext4_orphan_del(handle, inode);
5361 orphan = 0;
5358 ext4_journal_stop(handle); 5362 ext4_journal_stop(handle);
5359 goto err_out; 5363 goto err_out;
5360 } 5364 }
@@ -5377,7 +5381,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
5377 * If the call to ext4_truncate failed to get a transaction handle at 5381 * If the call to ext4_truncate failed to get a transaction handle at
5378 * all, we need to clean up the in-core orphan list manually. 5382 * all, we need to clean up the in-core orphan list manually.
5379 */ 5383 */
5380 if (inode->i_nlink) 5384 if (orphan && inode->i_nlink)
5381 ext4_orphan_del(NULL, inode); 5385 ext4_orphan_del(NULL, inode);
5382 5386
5383 if (!rc && (ia_valid & ATTR_MODE)) 5387 if (!rc && (ia_valid & ATTR_MODE))