From 7d4db05445578bd714e10a2af2d796764bab9802 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 11 May 2022 14:06:02 -0700 Subject: [PATCH] Add scoutfs_item_lookup_smaller_zero Add a lookup variant that returns an error if the item value is larger than the caller's value buffer size and which zeros the rest of the caller's buffer if the returned value is smaller. Signed-off-by: Zach Brown --- kmod/src/item.c | 33 ++++++++++++++++++++++++++++++--- kmod/src/item.h | 2 ++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/kmod/src/item.c b/kmod/src/item.c index a99202cf..9ec5aad0 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -1720,8 +1720,8 @@ static int copy_val(void *dst, int dst_len, void *src, int src_len) * The amount of bytes copied is returned which can be 0 or truncated if * the caller's buffer isn't big enough. */ -int scoutfs_item_lookup(struct super_block *sb, struct scoutfs_key *key, - void *val, int val_len, struct scoutfs_lock *lock) +static int item_lookup(struct super_block *sb, struct scoutfs_key *key, + void *val, int val_len, int len_limit, struct scoutfs_lock *lock) { DECLARE_ITEM_CACHE_INFO(sb, cinf); struct cached_item *item; @@ -1741,6 +1741,8 @@ int scoutfs_item_lookup(struct super_block *sb, struct scoutfs_key *key, item = item_rbtree_walk(&pg->item_root, key, NULL, NULL, NULL); if (!item || item->deletion) ret = -ENOENT; + else if (len_limit > 0 && item->val_len > len_limit) + ret = -EIO; else ret = copy_val(val, val_len, item->val, item->val_len); @@ -1749,13 +1751,38 @@ out: return ret; } +int scoutfs_item_lookup(struct super_block *sb, struct scoutfs_key *key, + void *val, int val_len, struct scoutfs_lock *lock) +{ + return item_lookup(sb, key, val, val_len, 0, lock); +} + +/* + * Copy an item's value into the caller's buffer. If the item's value + * is larger than the caller's buffer then -EIO is returned. If the + * item is smaller then the bytes from the end of the copied value to + * the end of the buffer are zeroed. The number of value bytes copied + * is returned, and 0 can be returned for an item with no value. + */ +int scoutfs_item_lookup_smaller_zero(struct super_block *sb, struct scoutfs_key *key, + void *val, int val_len, struct scoutfs_lock *lock) +{ + int ret; + + ret = item_lookup(sb, key, val, val_len, val_len, lock); + if (ret >= 0 && ret < val_len) + memset(val + ret, 0, val_len - ret); + + return ret; +} + int scoutfs_item_lookup_exact(struct super_block *sb, struct scoutfs_key *key, void *val, int val_len, struct scoutfs_lock *lock) { int ret; - ret = scoutfs_item_lookup(sb, key, val, val_len, lock); + ret = item_lookup(sb, key, val, val_len, 0, lock); if (ret == val_len) ret = 0; else if (ret >= 0) diff --git a/kmod/src/item.h b/kmod/src/item.h index d7fe6a2e..abadc90a 100644 --- a/kmod/src/item.h +++ b/kmod/src/item.h @@ -3,6 +3,8 @@ int scoutfs_item_lookup(struct super_block *sb, struct scoutfs_key *key, void *val, int val_len, struct scoutfs_lock *lock); +int scoutfs_item_lookup_smaller_zero(struct super_block *sb, struct scoutfs_key *key, + void *val, int val_len, struct scoutfs_lock *lock); int scoutfs_item_lookup_exact(struct super_block *sb, struct scoutfs_key *key, void *val, int val_len, struct scoutfs_lock *lock);