diff --git a/kmod/src/counters.h b/kmod/src/counters.h index 86787796..186a57d7 100644 --- a/kmod/src/counters.h +++ b/kmod/src/counters.h @@ -28,6 +28,7 @@ EXPAND_COUNTER(item_lookup_hit) \ EXPAND_COUNTER(item_lookup_miss) \ EXPAND_COUNTER(item_delete) \ + EXPAND_COUNTER(item_forget) \ EXPAND_COUNTER(item_range_hit) \ EXPAND_COUNTER(item_range_miss) \ EXPAND_COUNTER(item_range_insert) diff --git a/kmod/src/item.c b/kmod/src/item.c index 538b3ce1..23516168 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -1105,6 +1105,32 @@ out: return ret; } +/* + * Forcefully remove an item from the cache regardless of its state or + * relationship to persistent items. + * + * The caller is entirely responsible for the correctness of having this + * item vanish. + */ +void scoutfs_item_forget(struct super_block *sb, struct scoutfs_key_buf *key) +{ + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct item_cache *cac = sbi->item_cache; + struct cached_item *item; + unsigned long flags; + + spin_lock_irqsave(&cac->lock, flags); + + item = find_item(sb, &cac->items, key); + if (item) { + trace_printk("forgetting item %p\n", item); + scoutfs_inc_counter(sb, item_forget); + erase_item(sb, cac, item); + } + + spin_unlock_irqrestore(&cac->lock, flags); +} + /* * 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 8f84389a..4ca4d088 100644 --- a/kmod/src/item.h +++ b/kmod/src/item.h @@ -31,6 +31,7 @@ void scoutfs_item_delete_dirty(struct super_block *sb, 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); +void scoutfs_item_forget(struct super_block *sb, struct scoutfs_key_buf *key); int scoutfs_item_add_batch(struct super_block *sb, struct list_head *list, struct scoutfs_key_buf *key, struct kvec *val);