Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: fix to adapt small inline xattr space in __find_inline_xattr()

With below testcase, we will fail to find existed xattr entry:

1. mkfs.f2fs -O extra_attr -O flexible_inline_xattr /dev/zram0
2. mount -t f2fs -o inline_xattr_size=1 /dev/zram0 /mnt/f2fs/
3. touch /mnt/f2fs/file
4. setfattr -n "user.name" -v 0 /mnt/f2fs/file
5. getfattr -n "user.name" /mnt/f2fs/file

/mnt/f2fs/file: user.name: No such attribute

The reason is for inode which has very small inline xattr size,
__find_inline_xattr() will fail to traverse any entry due to first
entry may not be loaded from xattr node yet, later, we may skip to
check entire xattr datas in __find_xattr(), result in such wrong
condition.

This patch adds condition to check such case to avoid this issue.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Chao Yu and committed by
Jaegeuk Kim
2c28aba8 dd6c89b5

+10 -3
+10 -3
fs/f2fs/xattr.c
··· 224 224 { 225 225 struct f2fs_xattr_entry *entry; 226 226 unsigned int inline_size = inline_xattr_size(inode); 227 + void *max_addr = base_addr + inline_size; 227 228 228 229 list_for_each_xattr(entry, base_addr) { 229 - if ((void *)entry + sizeof(__u32) > base_addr + inline_size || 230 - (void *)XATTR_NEXT_ENTRY(entry) + sizeof(__u32) > 231 - base_addr + inline_size) { 230 + if ((void *)entry + sizeof(__u32) > max_addr || 231 + (void *)XATTR_NEXT_ENTRY(entry) > max_addr) { 232 232 *last_addr = entry; 233 233 return NULL; 234 234 } ··· 238 238 continue; 239 239 if (!memcmp(entry->e_name, name, len)) 240 240 break; 241 + } 242 + 243 + /* inline xattr header or entry across max inline xattr size */ 244 + if (IS_XATTR_LAST_ENTRY(entry) && 245 + (void *)entry + sizeof(__u32) > max_addr) { 246 + *last_addr = entry; 247 + return NULL; 241 248 } 242 249 return entry; 243 250 }