f2fs: enhance lookup xattr
Previously, in getxattr we will load all entries both in inline xattr and xattr node block, and then do the lookup in all entries, but our lookup flow shows low efficiency, since if we can lookup and hit in inline xattr of inode page cache first, we don't need to load and lookup xattr node block, which can obviously save cpu time and IO latency. Signed-off-by: Chao Yu <yuchao0@huawei.com> [Jaegeuk Kim: initialize NULL to avoid warning] Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Родитель
04b9a5f0f5
Коммит
ba38c27eb9
132
fs/f2fs/xattr.c
132
fs/f2fs/xattr.c
|
@ -217,6 +217,112 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr,
|
||||||
|
void **last_addr, int index,
|
||||||
|
size_t len, const char *name)
|
||||||
|
{
|
||||||
|
struct f2fs_xattr_entry *entry;
|
||||||
|
unsigned int inline_size = F2FS_INLINE_XATTR_ADDRS << 2;
|
||||||
|
|
||||||
|
list_for_each_xattr(entry, base_addr) {
|
||||||
|
if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
|
||||||
|
(void *)XATTR_NEXT_ENTRY(entry) + sizeof(__u32) >
|
||||||
|
base_addr + inline_size) {
|
||||||
|
*last_addr = entry;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (entry->e_name_index != index)
|
||||||
|
continue;
|
||||||
|
if (entry->e_name_len != len)
|
||||||
|
continue;
|
||||||
|
if (!memcmp(entry->e_name, name, len))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||||
|
unsigned int index, unsigned int len,
|
||||||
|
const char *name, struct f2fs_xattr_entry **xe,
|
||||||
|
void **base_addr)
|
||||||
|
{
|
||||||
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
|
void *cur_addr, *txattr_addr, *last_addr = NULL;
|
||||||
|
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
|
||||||
|
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
|
||||||
|
unsigned int inline_size = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
inline_size = inline_xattr_size(inode);
|
||||||
|
|
||||||
|
if (!size && !inline_size)
|
||||||
|
return -ENODATA;
|
||||||
|
|
||||||
|
txattr_addr = kzalloc(inline_size + size + sizeof(__u32),
|
||||||
|
GFP_F2FS_ZERO);
|
||||||
|
if (!txattr_addr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* read from inline xattr */
|
||||||
|
if (inline_size) {
|
||||||
|
struct page *page = NULL;
|
||||||
|
void *inline_addr;
|
||||||
|
|
||||||
|
if (ipage) {
|
||||||
|
inline_addr = inline_xattr_addr(ipage);
|
||||||
|
} else {
|
||||||
|
page = get_node_page(sbi, inode->i_ino);
|
||||||
|
if (IS_ERR(page)) {
|
||||||
|
err = PTR_ERR(page);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
inline_addr = inline_xattr_addr(page);
|
||||||
|
}
|
||||||
|
memcpy(txattr_addr, inline_addr, inline_size);
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
|
||||||
|
*xe = __find_inline_xattr(txattr_addr, &last_addr,
|
||||||
|
index, len, name);
|
||||||
|
if (*xe)
|
||||||
|
goto check;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read from xattr node block */
|
||||||
|
if (xnid) {
|
||||||
|
struct page *xpage;
|
||||||
|
void *xattr_addr;
|
||||||
|
|
||||||
|
/* The inode already has an extended attribute block. */
|
||||||
|
xpage = get_node_page(sbi, xnid);
|
||||||
|
if (IS_ERR(xpage)) {
|
||||||
|
err = PTR_ERR(xpage);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
xattr_addr = page_address(xpage);
|
||||||
|
memcpy(txattr_addr + inline_size, xattr_addr, size);
|
||||||
|
f2fs_put_page(xpage, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_addr)
|
||||||
|
cur_addr = XATTR_HDR(last_addr) - 1;
|
||||||
|
else
|
||||||
|
cur_addr = txattr_addr;
|
||||||
|
|
||||||
|
*xe = __find_xattr(cur_addr, index, len, name);
|
||||||
|
check:
|
||||||
|
if (IS_XATTR_LAST_ENTRY(*xe)) {
|
||||||
|
err = -ENODATA;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*base_addr = txattr_addr;
|
||||||
|
return 0;
|
||||||
|
out:
|
||||||
|
kzfree(txattr_addr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int read_all_xattrs(struct inode *inode, struct page *ipage,
|
static int read_all_xattrs(struct inode *inode, struct page *ipage,
|
||||||
void **base_addr)
|
void **base_addr)
|
||||||
{
|
{
|
||||||
|
@ -348,8 +454,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
xattr_addr = page_address(xpage);
|
xattr_addr = page_address(xpage);
|
||||||
memcpy(xattr_addr, txattr_addr + inline_size, PAGE_SIZE -
|
memcpy(xattr_addr, txattr_addr + inline_size, MAX_XATTR_BLOCK_SIZE);
|
||||||
sizeof(struct node_footer));
|
|
||||||
set_page_dirty(xpage);
|
set_page_dirty(xpage);
|
||||||
f2fs_put_page(xpage, 1);
|
f2fs_put_page(xpage, 1);
|
||||||
|
|
||||||
|
@ -361,10 +466,11 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||||
int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||||
void *buffer, size_t buffer_size, struct page *ipage)
|
void *buffer, size_t buffer_size, struct page *ipage)
|
||||||
{
|
{
|
||||||
struct f2fs_xattr_entry *entry;
|
struct f2fs_xattr_entry *entry = NULL;
|
||||||
void *base_addr;
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
size_t size, len;
|
unsigned int size, len;
|
||||||
|
char *pval;
|
||||||
|
void *base_addr = NULL;
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -373,30 +479,26 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||||
if (len > F2FS_NAME_LEN)
|
if (len > F2FS_NAME_LEN)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
error = read_all_xattrs(inode, ipage, &base_addr);
|
error = lookup_all_xattrs(inode, ipage, index, len, name,
|
||||||
|
&entry, &base_addr);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
entry = __find_xattr(base_addr, index, len, name);
|
|
||||||
if (IS_XATTR_LAST_ENTRY(entry)) {
|
|
||||||
error = -ENODATA;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = le16_to_cpu(entry->e_value_size);
|
size = le16_to_cpu(entry->e_value_size);
|
||||||
|
|
||||||
if (buffer && size > buffer_size) {
|
if (buffer && size > buffer_size) {
|
||||||
error = -ERANGE;
|
error = -ERANGE;
|
||||||
goto cleanup;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pval = entry->e_name + entry->e_name_len;
|
||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
char *pval = entry->e_name + entry->e_name_len;
|
char *pval = entry->e_name + entry->e_name_len;
|
||||||
memcpy(buffer, pval, size);
|
memcpy(buffer, pval, size);
|
||||||
}
|
}
|
||||||
error = size;
|
error = size;
|
||||||
|
out:
|
||||||
cleanup:
|
|
||||||
kzfree(base_addr);
|
kzfree(base_addr);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,10 @@ struct f2fs_xattr_entry {
|
||||||
for (entry = XATTR_FIRST_ENTRY(addr);\
|
for (entry = XATTR_FIRST_ENTRY(addr);\
|
||||||
!IS_XATTR_LAST_ENTRY(entry);\
|
!IS_XATTR_LAST_ENTRY(entry);\
|
||||||
entry = XATTR_NEXT_ENTRY(entry))
|
entry = XATTR_NEXT_ENTRY(entry))
|
||||||
|
#define MAX_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer))
|
||||||
#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + PAGE_SIZE - \
|
#define VALID_XATTR_BLOCK_SIZE (MAX_XATTR_BLOCK_SIZE - sizeof(__u32))
|
||||||
sizeof(struct node_footer) - sizeof(__u32))
|
#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \
|
||||||
|
VALID_XATTR_BLOCK_SIZE)
|
||||||
|
|
||||||
#define MAX_VALUE_LEN(i) (MIN_OFFSET(i) - \
|
#define MAX_VALUE_LEN(i) (MIN_OFFSET(i) - \
|
||||||
sizeof(struct f2fs_xattr_header) - \
|
sizeof(struct f2fs_xattr_header) - \
|
||||||
|
|
Загрузка…
Ссылка в новой задаче