mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-10 01:56:09 +00:00
scoutfs: revive item deletion path
The inode deletion path had bit rotted. Delete the ifdefs that were stopping it from deleting all the items associated with an inode. There can be a lot of xattr and data mapping items so we have them manage their own transactions (data already did). The xattr deletion code was trying to get a lock while the caller already held it so delete that. Then we accurately account for the small number of remaining items that finally delete the inode. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -117,6 +117,24 @@ static inline const struct scoutfs_item_count SIC_MKNOD(unsigned name_len)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dropping the inode deletes all its items. Potentially enormous numbers
|
||||
* of items (data mapping, xattrs) are deleted in their own transactions.
|
||||
*/
|
||||
static inline const struct scoutfs_item_count SIC_DROP_INODE(int mode,
|
||||
u64 size)
|
||||
{
|
||||
struct scoutfs_item_count cnt = {0,};
|
||||
|
||||
if (S_ISLNK(mode))
|
||||
__count_sym_target(&cnt, size);
|
||||
__count_dirty_inode(&cnt);
|
||||
__count_orphan(&cnt);
|
||||
|
||||
cnt.vals = 0;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static inline const struct scoutfs_item_count SIC_LINK(unsigned name_len)
|
||||
{
|
||||
struct scoutfs_item_count cnt = {0,};
|
||||
|
||||
+22
-16
@@ -1400,6 +1400,7 @@ static int delete_inode_items(struct super_block *sb, u64 ino)
|
||||
struct kvec val;
|
||||
umode_t mode;
|
||||
u64 ind_seq;
|
||||
u64 size;
|
||||
int ret;
|
||||
|
||||
ret = scoutfs_lock_ino(sb, DLM_LOCK_EX, 0, ino, &lock);
|
||||
@@ -1424,14 +1425,27 @@ static int delete_inode_items(struct super_block *sb, u64 ino)
|
||||
}
|
||||
|
||||
mode = le32_to_cpu(sinode.mode);
|
||||
trace_scoutfs_delete_inode(sb, ino, mode);
|
||||
size = le64_to_cpu(sinode.size);
|
||||
trace_scoutfs_delete_inode(sb, ino, mode, size);
|
||||
|
||||
/* XXX the trans reservation count is obviously bonkers :) */
|
||||
/* remove data items in their own transactions */
|
||||
if (S_ISREG(mode)) {
|
||||
ret = scoutfs_data_truncate_items(sb, NULL, ino, 0, ~0ULL,
|
||||
false, lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_xattr_drop(sb, ino, lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* then delete the small known number of remaining inode items */
|
||||
retry:
|
||||
ret = scoutfs_inode_index_start(sb, &ind_seq) ?:
|
||||
prepare_index_deletion(sb, &ind_locks, ino, mode, &sinode) ?:
|
||||
scoutfs_inode_index_try_lock_hold(sb, &ind_locks, ind_seq,
|
||||
SIC_DIRTY_INODE());
|
||||
SIC_DROP_INODE(mode, size));
|
||||
if (ret > 0)
|
||||
goto retry;
|
||||
if (ret)
|
||||
@@ -1439,24 +1453,16 @@ retry:
|
||||
|
||||
release = true;
|
||||
|
||||
/* first remove index items to try to avoid indexing partial deletion */
|
||||
ret = remove_index_items(sb, ino, &sinode, &ind_locks);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
#if 0
|
||||
ret = scoutfs_xattr_drop(sb, ino);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (S_ISLNK(mode)) {
|
||||
ret = scoutfs_symlink_drop(sb, ino, lock, size);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISLNK(mode))
|
||||
ret = scoutfs_symlink_drop(sb, ino, i_size);
|
||||
else if (S_ISREG(mode))
|
||||
ret = scoutfs_truncate_extent_items(sb, ino, 0, ~0ULL, false);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
#endif
|
||||
ret = scoutfs_item_delete(sb, &key, lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -1296,24 +1296,27 @@ TRACE_EVENT(scoutfs_orphan_inode,
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_delete_inode,
|
||||
TP_PROTO(struct super_block *sb, u64 ino, umode_t mode),
|
||||
TP_PROTO(struct super_block *sb, u64 ino, umode_t mode, u64 size),
|
||||
|
||||
TP_ARGS(sb, ino, mode),
|
||||
TP_ARGS(sb, ino, mode, size),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(__u64, ino)
|
||||
__field(umode_t, mode)
|
||||
__field(__u64, size)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = sb->s_dev;
|
||||
__entry->ino = ino;
|
||||
__entry->mode = mode;
|
||||
__entry->size = size;
|
||||
),
|
||||
|
||||
TP_printk("dev %d,%d ino %llu, mode 0x%x", MAJOR(__entry->dev),
|
||||
MINOR(__entry->dev), __entry->ino, __entry->mode)
|
||||
TP_printk("dev %d,%d ino %llu, mode 0x%x size %llu",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino,
|
||||
__entry->mode, __entry->size)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_scan_orphans,
|
||||
|
||||
+25
-15
@@ -554,46 +554,56 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all the xattr items associated with this inode. The caller
|
||||
* holds a transaction. The inode is dead so we don't need the xattr
|
||||
* rwsem.
|
||||
* Delete all the xattr items associated with this inode. The inode is
|
||||
* dead so we don't need the xattr rwsem.
|
||||
*
|
||||
* XXX This isn't great because it reads in all the items so that it can
|
||||
* create deletion items for each. It would be better to have the
|
||||
* caller create range deletion items for all the items covered by the
|
||||
* inode. That wouldn't require reading at all.
|
||||
*/
|
||||
int scoutfs_xattr_drop(struct super_block *sb, u64 ino)
|
||||
int scoutfs_xattr_drop(struct super_block *sb, u64 ino,
|
||||
struct scoutfs_lock *lock)
|
||||
{
|
||||
struct scoutfs_key last;
|
||||
struct scoutfs_key key;
|
||||
struct scoutfs_lock *lck;
|
||||
unsigned int items = 16;
|
||||
bool holding = false;
|
||||
int ret;
|
||||
|
||||
init_xattr_key(&key, ino, 0, 0);
|
||||
init_xattr_key(&last, ino, U32_MAX, U64_MAX);
|
||||
|
||||
/* while we read to delete we need to writeback others */
|
||||
ret = scoutfs_lock_ino(sb, DLM_LOCK_EX, 0, ino, &lck);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
for (;;) {
|
||||
ret = scoutfs_item_next(sb, &key, &last, NULL, lck);
|
||||
ret = scoutfs_item_next(sb, &key, &last, NULL, lock);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = scoutfs_item_delete(sb, &key, lck);
|
||||
if (!holding) {
|
||||
ret = scoutfs_hold_trans(sb, SIC_EXACT(items, 0));
|
||||
if (ret)
|
||||
break;
|
||||
holding = true;
|
||||
}
|
||||
|
||||
ret = scoutfs_item_delete(sb, &key, lock);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
key.skx_part++;
|
||||
if (--items == 0) {
|
||||
scoutfs_release_trans(sb);
|
||||
holding = false;
|
||||
items = 16;
|
||||
}
|
||||
|
||||
/* don't need to inc, next won't see deleted item */
|
||||
}
|
||||
|
||||
scoutfs_unlock(sb, lck, DLM_LOCK_EX);
|
||||
out:
|
||||
if (holding)
|
||||
scoutfs_release_trans(sb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@ int scoutfs_setxattr(struct dentry *dentry, const char *name,
|
||||
int scoutfs_removexattr(struct dentry *dentry, const char *name);
|
||||
ssize_t scoutfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
|
||||
int scoutfs_xattr_drop(struct super_block *sb, u64 ino);
|
||||
int scoutfs_xattr_drop(struct super_block *sb, u64 ino,
|
||||
struct scoutfs_lock *lock);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user