From 9a293bfa758797ecb92c1aaf22e092dd6b4cf5ff Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 25 Jan 2017 11:08:43 -0800 Subject: [PATCH] Add item delete dirty and many interfaces Add item functions for deleting items that we know to be dirty and add a user in another function that deletes many items without leaving parial deletions behind in the case of errors. Signed-off-by: Zach Brown --- kmod/src/item.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++--- kmod/src/item.h | 4 +++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/kmod/src/item.c b/kmod/src/item.c index c4dff761..d471cab6 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -964,6 +964,23 @@ out: return ret; } +/* + * Turn an item that the caller has found while holding the lock into a + * deletion item. The caller will free whatever we put in the deletion + * value after releasing the lock. + */ +static void become_deletion_item(struct super_block *sb, + struct item_cache *cac, + struct cached_item *item, + struct kvec *del_val) +{ + scoutfs_kvec_clone(del_val, item->val); + scoutfs_kvec_init_null(item->val); + item->deletion = 1; + mark_item_dirty(cac, item); + scoutfs_inc_counter(sb, item_delete); +} + /* * Delete an existing item with the given key. * @@ -999,10 +1016,7 @@ int scoutfs_item_delete(struct super_block *sb, struct scoutfs_key_buf *key) item = find_item(sb, &cac->items, key); if (item) { - scoutfs_kvec_swap(item->val, del_val); - item->deletion = 1; - mark_item_dirty(cac, item); - scoutfs_inc_counter(sb, item_delete); + become_deletion_item(sb, cac, item, del_val); ret = 0; } else if (check_range(sb, &cac->ranges, key, end)) { ret = -ENOENT; @@ -1022,6 +1036,62 @@ out: return ret; } +/* + * Delete an item that the caller knows must be dirty because they hold + * locks and the transaction and have created or dirtied it. This can't + * fail. + */ +void scoutfs_item_delete_dirty(struct super_block *sb, + struct scoutfs_key_buf *key) +{ + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct item_cache *cac = sbi->item_cache; + SCOUTFS_DECLARE_KVEC(del_val); + struct cached_item *item; + unsigned long flags; + + scoutfs_kvec_init_null(del_val); + + spin_lock_irqsave(&cac->lock, flags); + + item = find_item(sb, &cac->items, key); + if (item) + become_deletion_item(sb, cac, item, del_val); + + spin_unlock_irqrestore(&cac->lock, flags); + + scoutfs_kvec_kfree(del_val); +} + +/* + * A helper that deletes a set of items. It first dirties the items + * will be pinned so that deletion won't fail as it tries to read and + * populate the items. + * + * It's a little cleaner to have this helper than have the caller + * iterate, but it could also give us the opportunity to reduce item + * searches if we remembered the items we dirtied. + */ +int scoutfs_item_delete_many(struct super_block *sb, + struct scoutfs_key_buf **keys, unsigned nr) +{ + int ret = 0; + int i; + + for (i = 0; i < nr; i++) { + ret = scoutfs_item_dirty(sb, keys[i]); + if (ret) + goto out; + } + + for (i = 0; i < nr; i++) + scoutfs_item_delete_dirty(sb, keys[i]); + +out: + trace_printk("ret %d\n", ret); + return ret; +} + /* * Return the first dirty node in the subtree starting at the given node. */ diff --git a/kmod/src/item.h b/kmod/src/item.h index 02afc91c..8f84389a 100644 --- a/kmod/src/item.h +++ b/kmod/src/item.h @@ -26,6 +26,10 @@ int scoutfs_item_create(struct super_block *sb, struct scoutfs_key_buf *key, int scoutfs_item_dirty(struct super_block *sb, struct scoutfs_key_buf *key); int scoutfs_item_update(struct super_block *sb, struct scoutfs_key_buf *key, struct kvec *val); +void scoutfs_item_delete_dirty(struct super_block *sb, + struct scoutfs_key_buf *key); +int scoutfs_item_delete_many(struct super_block *sb, + struct scoutfs_key_buf **keys, unsigned nr); int scoutfs_item_delete(struct super_block *sb, struct scoutfs_key_buf *key); int scoutfs_item_add_batch(struct super_block *sb, struct list_head *list,