diff options
| author | Dmitry Monakhov <dmonakhov@openvz.org> | 2010-10-27 22:08:46 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2010-10-27 22:08:46 -0400 |
| commit | 3d287de3b828226e5a450c7fd5bf4283792dc2b0 (patch) | |
| tree | 4adcc534e2042aed924750df3ef2433bd2f14fd8 | |
| parent | beed5ecbaa377fa8bb6a54a6608e8725a21efdbc (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>
| -rw-r--r-- | fs/ext4/inode.c | 10 |
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)) |
