-
Notifications
You must be signed in to change notification settings - Fork 9
Do orphaned inode extent freeing in chunks #231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -468,8 +468,8 @@ int scoutfs_complete_truncate(struct inode *inode, struct scoutfs_lock *lock) | |
| start = (i_size_read(inode) + SCOUTFS_BLOCK_SM_SIZE - 1) >> | ||
| SCOUTFS_BLOCK_SM_SHIFT; | ||
| ret = scoutfs_data_truncate_items(inode->i_sb, inode, | ||
| scoutfs_ino(inode), start, ~0ULL, | ||
| false, lock); | ||
| scoutfs_ino(inode), &start, ~0ULL, | ||
| false, lock, false); | ||
| err = clear_truncate_flag(inode, lock); | ||
|
|
||
| return ret ? ret : err; | ||
|
|
@@ -1635,7 +1635,8 @@ int scoutfs_inode_orphan_delete(struct super_block *sb, u64 ino, struct scoutfs_ | |
| * partial deletion until all deletion is complete and the orphan item | ||
| * is removed. | ||
| */ | ||
| static int delete_inode_items(struct super_block *sb, u64 ino, struct scoutfs_inode *sinode, | ||
| static int delete_inode_items(struct super_block *sb, u64 ino, | ||
| struct scoutfs_inode *sinode, u64 *start, | ||
| struct scoutfs_lock *lock, struct scoutfs_lock *orph_lock) | ||
| { | ||
| struct scoutfs_key key; | ||
|
|
@@ -1654,8 +1655,8 @@ static int delete_inode_items(struct super_block *sb, u64 ino, struct scoutfs_in | |
|
|
||
| /* remove data items in their own transactions */ | ||
| if (S_ISREG(mode)) { | ||
| ret = scoutfs_data_truncate_items(sb, NULL, ino, 0, ~0ULL, | ||
| false, lock); | ||
| ret = scoutfs_data_truncate_items(sb, NULL, ino, start, ~0ULL, | ||
| false, lock, true); | ||
| if (ret) | ||
| goto out; | ||
| } | ||
|
|
@@ -1803,16 +1804,23 @@ static int get_current_lock_data(struct super_block *sb, struct scoutfs_lock *lo | |
| */ | ||
| static int try_delete_inode_items(struct super_block *sb, u64 ino) | ||
| { | ||
| struct inode_deletion_lock_data *ldata = NULL; | ||
| struct scoutfs_lock *orph_lock = NULL; | ||
| struct scoutfs_lock *lock = NULL; | ||
| struct inode_deletion_lock_data *ldata; | ||
| struct scoutfs_lock *orph_lock; | ||
| struct scoutfs_lock *lock; | ||
| struct scoutfs_inode sinode; | ||
| struct scoutfs_key key; | ||
| bool clear_trying = false; | ||
| bool more = false; | ||
| u64 group_nr; | ||
| u64 start = 0; | ||
| int bit_nr; | ||
| int ret; | ||
|
|
||
| again: | ||
| ldata = NULL; | ||
| orph_lock = NULL; | ||
| lock = NULL; | ||
|
|
||
| ret = scoutfs_lock_ino(sb, SCOUTFS_LOCK_WRITE, 0, ino, &lock); | ||
| if (ret < 0) | ||
| goto out; | ||
|
|
@@ -1824,11 +1832,12 @@ static int try_delete_inode_items(struct super_block *sb, u64 ino) | |
| goto out; | ||
|
|
||
| /* only one local attempt per inode at a time */ | ||
| if (test_and_set_bit(bit_nr, ldata->trying)) { | ||
| if (!more && test_and_set_bit(bit_nr, ldata->trying)) { | ||
| ret = 0; | ||
| goto out; | ||
| } | ||
| clear_trying = true; | ||
| more = false; | ||
|
|
||
| /* can't delete if it's cached in local or remote mounts */ | ||
| if (scoutfs_omap_test(sb, ino) || test_bit_le(bit_nr, ldata->map.bits)) { | ||
|
|
@@ -1853,14 +1862,25 @@ static int try_delete_inode_items(struct super_block *sb, u64 ino) | |
| if (ret < 0) | ||
| goto out; | ||
|
|
||
| ret = delete_inode_items(sb, ino, &sinode, lock, orph_lock); | ||
| ret = delete_inode_items(sb, ino, &sinode, &start, lock, orph_lock); | ||
|
|
||
| if (ret == -EINPROGRESS) { | ||
| more = true; | ||
| clear_trying = false; | ||
| } else { | ||
| more = false; | ||
| } | ||
|
|
||
| out: | ||
| if (clear_trying) | ||
| clear_bit(bit_nr, ldata->trying); | ||
|
|
||
| scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE); | ||
| scoutfs_unlock(sb, orph_lock, SCOUTFS_LOCK_WRITE_ONLY); | ||
|
|
||
| if (more) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding this loop without clearing more at the start makes me nervous. It certainly looks like it'll loop forever if any of the errors before more is cleared are returned (perhaps from shutdown or forced unmount returning blanket errors from net/io paths). I'd rather not bother with this additional loop and would instead make sure to do enough work per iteration that we don't mind returning to the caller and letting them use their existing retry mechanisms. |
||
| goto again; | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -372,9 +372,9 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) | |
| sblock = args.offset >> SCOUTFS_BLOCK_SM_SHIFT; | ||
| eblock = (args.offset + args.length - 1) >> SCOUTFS_BLOCK_SM_SHIFT; | ||
| ret = scoutfs_data_truncate_items(sb, inode, scoutfs_ino(inode), | ||
| sblock, | ||
| &sblock, | ||
| eblock, true, | ||
| lock); | ||
| lock, false); | ||
| if (ret == 0) { | ||
| scoutfs_inode_get_onoff(inode, &online, &offline); | ||
| isize = i_size_read(inode); | ||
|
|
@@ -383,8 +383,8 @@ static long scoutfs_ioc_release(struct file *file, unsigned long arg) | |
| >> SCOUTFS_BLOCK_SM_SHIFT; | ||
| ret = scoutfs_data_truncate_items(sb, inode, | ||
| scoutfs_ino(inode), | ||
| sblock, U64_MAX, | ||
| false, lock); | ||
| &sblock, U64_MAX, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These changes make me nervous. This used to obviously always truncate (s,e) and (s, ~0). Now it probably truncates from (s, e) and (e, ~0), but we'd have to go diving into the implementation to make sure there isn't some accidental final increment before returning that means it actually truncates (e + 1, ~0), or whatever. Let's avoid this pattern as much as possible. (It's why truncate_extent_items() returns the block number instead of updating an arg. This lesson was learned over and over in the kernel with the *ppos arguments to write functions that sometimes updated write pointers, or not, and was a nightmare.) |
||
| false, lock, false); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| == setting longer hung task timeout | ||
| == creating fragmented extents | ||
| == unlink file with moved extents to free extents per block | ||
| == cleanup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this function has gotten to the point where it's no longer helpful shared code with some differences, but acctually two different things interleaved with conditionals. Instead of also letting it make partial progress, let's split it into two functions: this that truncates live inodes and requires the inode pointer, and a new _data_free_items that is specifically built to remove a transaction's worth of extents and then return. It wouldn't need any of the arguments -- it'd always start at 0 and remove whatever it finds.