[RFC PATCH v2 2/3] UBIFS: ACL: add ACL support
Sheng Yong
shengyong1 at huawei.com
Mon Sep 7 02:02:19 PDT 2015
Hi, Dongsheng
On 9/7/2015 4:06 PM, Dongsheng Yang wrote:
> On 09/07/2015 01:40 AM, Sheng Yong wrote:
[...]
>> +
>> +#define UBIFS_ACL_VERSION 0x0001
>> +
>> +struct ubifs_acl_entry {
>> + __le16 e_tag;
>> + __le16 e_perm;
>> + __le32 e_id;
>> +};
>> +
>> +struct ubifs_acl_entry_short {
>> + __le16 e_tag;
>> + __le16 e_perm;
>> +};
>> +
>> +struct ubifs_acl_header {
>> + __le32 a_version;
>> +};
>> +
>> +#define UBIFS_ACL_HEADER_SZ sizeof(struct ubifs_acl_header)
>> +#define UBIFS_ACL_ENTRY_SZ sizeof(struct ubifs_acl_entry)
>> +#define UBIFS_ACL_ENTRY_SHORT_SZ sizeof(struct ubifs_acl_entry_short)
> Hi Sheng,
> I found you define some structures different with
> the generic posix_acl, why? Please explain as much as
> possible, it's helpful for review.
>
Thanks for your review.
The above struct looks like the generic posix ones. But the data types of the
struct's members should be considered. The in-memory ACL format may be different
from the on-flash ACL format, because of endian issue. Different compiler may
have different endian settings. The FS image may broke on a different architecture
because of endian. So here we have to define file system specific structures to
save ACL values. And this is way we have to do ACL conversion between in-memory and
on-flash.
thanks,
Sheng
>> +
>> +static inline size_t acl_size(int count)
>> +{
>> + if (count <= 4) {
>> + return UBIFS_ACL_HEADER_SZ +
>> + count * UBIFS_ACL_ENTRY_SHORT_SZ;
>> + } else {
>> + return UBIFS_ACL_HEADER_SZ +
>> + 4 * UBIFS_ACL_ENTRY_SHORT_SZ +
>> + (count - 4) * UBIFS_ACL_ENTRY_SZ;
>> + }
>> +}
>> +
>> +static inline int acl_count(size_t size)
>> +{
>> + ssize_t s;
>> +
>> + size -= UBIFS_ACL_HEADER_SZ;
>> + s = size - 4 * UBIFS_ACL_ENTRY_SHORT_SZ;
>> + if (s < 0) {
>> + if (size % UBIFS_ACL_ENTRY_SHORT_SZ)
>> + return -1;
>> + return size / UBIFS_ACL_ENTRY_SHORT_SZ;
>> + } else {
>> + if (s % UBIFS_ACL_ENTRY_SZ)
>> + return -1;
>> + return s / UBIFS_ACL_ENTRY_SZ + 4;
>> + }
>> +}
>> +
>> +/* convert from in-memory ACL to on-flash ACL */
>> +static void *acl_to_flash(const struct posix_acl *acl, size_t *size, int type)
>
> Why we need a special function here to do this conversion?
> Is posix_acl_[to|from]_xattr() not suitable for us? If yes,
> please add a comment here.
>
> Thanx
> Yang
>> +{
>> + struct ubifs_acl_header *hdr;
>> + struct ubifs_acl_entry *uae;
>> + int i;
>> +
>> + *size = acl_size(acl->a_count);
>> + hdr = kmalloc(*size, GFP_KERNEL);
>> + if (!hdr)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + hdr->a_version = cpu_to_le32(UBIFS_ACL_VERSION);
>> + uae = (struct ubifs_acl_entry *) (hdr + 1);
>> +
>> + for (i = 0; i < acl->a_count; i++) {
>> + const struct posix_acl_entry *ae = &acl->a_entries[i];
>> + uae->e_tag = cpu_to_le16(ae->e_tag);
>> + uae->e_perm = cpu_to_le16(ae->e_perm);
>> + switch (ae->e_tag) {
>> + case ACL_USER_OBJ:
>> + case ACL_GROUP_OBJ:
>> + case ACL_MASK:
>> + case ACL_OTHER:
>> + /* for the 4 options, id is not used */
>> + uae = (struct ubifs_acl_entry *) ((char *) uae +
>> + UBIFS_ACL_ENTRY_SHORT_SZ);
>> + break;
>> + case ACL_USER:
>> + {
>> + uid_t u = from_kuid(&init_user_ns, ae->e_uid);
>> + uae->e_id = cpu_to_le32(u);
>> + uae = (struct ubifs_acl_entry *) ((char *) uae +
>> + UBIFS_ACL_ENTRY_SZ);
>> + break;
>> + }
>> + case ACL_GROUP:
>> + {
>> + gid_t g = from_kgid(&init_user_ns, ae->e_gid);
>> + uae->e_id = cpu_to_le32(g);
>> + uae = (struct ubifs_acl_entry *) ((char *) uae +
>> + UBIFS_ACL_ENTRY_SZ);
>> + break;
>> + }
>> + default:
>> + goto fail;
>> + }
>> + }
>> +
>> + return (void *) hdr;
>> +
>> +fail:
>> + kfree(hdr);
>> + return ERR_PTR(-EINVAL);
>> +}
>> +
>> +/* convert from on-flash ACL to in-memory ACL */
>> +static struct posix_acl *acl_from_flash(const void *value, size_t size)
>> +{
>> + struct posix_acl *acl;
>> + struct ubifs_acl_header *hdr = (struct ubifs_acl_header *) value;
>> + struct ubifs_acl_entry *uae = (struct ubifs_acl_entry *) (hdr + 1);
>> + const char *end = value + size;
>> + int count, i;
>> +
>> + if (!value)
>> + return NULL;
>> + if (size < UBIFS_ACL_HEADER_SZ)
>> + return ERR_PTR(-EINVAL);
>> + if (hdr->a_version != cpu_to_le32(UBIFS_ACL_VERSION))
>> + return ERR_PTR(-EINVAL);
>> +
>> + count = acl_count(size);
>> + if (count < 0)
>> + return ERR_PTR(-EINVAL);
>> + if (count == 0)
>> + return NULL;
>> +
>> + acl = posix_acl_alloc(count, GFP_KERNEL);
>> + if (!acl)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + for (i = 0; i < count; i++) {
>> + if ((char *) uae > end)
>> + goto fail;
>> +
>> + acl->a_entries[i].e_tag = le16_to_cpu(uae->e_tag);
>> + acl->a_entries[i].e_perm = le16_to_cpu(uae->e_perm);
>> + switch (acl->a_entries[i].e_tag) {
>> + case ACL_USER_OBJ:
>> + case ACL_GROUP_OBJ:
>> + case ACL_MASK:
>> + case ACL_OTHER:
>> + /* for the 4 options, no id */
>> + uae = (struct ubifs_acl_entry *) ((char *) uae +
>> + UBIFS_ACL_ENTRY_SHORT_SZ);
>> + break;
>> + case ACL_USER:
>> + {
>> + uid_t u = le32_to_cpu(uae->e_id);
>> + acl->a_entries[i].e_uid = make_kuid(&init_user_ns, u);
>> + uae = (struct ubifs_acl_entry *) ((char *) uae +
>> + UBIFS_ACL_ENTRY_SZ);
>> + break;
>> + }
>> + case ACL_GROUP:
>> + {
>> + gid_t g = le32_to_cpu(uae->e_id);
>> + acl->a_entries[i].e_gid = make_kgid(&init_user_ns, g);
>> + uae = (struct ubifs_acl_entry *) ((char *) uae +
>> + UBIFS_ACL_ENTRY_SZ);
>> + break;
>> + }
>> + default:
>> + goto fail;
>> + }
>> + }
>> +
>> + if ((char *) uae != end)
>> + goto fail;
>> +
>> + return acl;
>> +
>> +fail:
>> + posix_acl_release(acl);
>> + return ERR_PTR(-EINVAL);
>> +}
>> +
>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type)
>> +{
>> + struct posix_acl *acl;
>> + char *name, *value = NULL;
>> + int size = 0;
>> +
>> + switch (type) {
>> + case ACL_TYPE_ACCESS:
>> + name = XATTR_NAME_POSIX_ACL_ACCESS;
>> + break;
>> + case ACL_TYPE_DEFAULT:
>> + name = XATTR_NAME_POSIX_ACL_DEFAULT;
>> + break;
>> + default:
>> + BUG();
>> + }
>> +
>> + size = ubifs_do_getxattr(inode, name, NULL, 0);
>> + if (size > 0) {
>> + value = kmalloc(size, GFP_KERNEL);
>> + if (!value)
>> + return ERR_PTR(-ENOMEM);
>> + size = ubifs_do_getxattr(inode, name, value, size);
>> + }
>> + if (size > 0)
>> + acl = acl_from_flash(value, size);
>> + else if (size == -ENODATA)
>> + acl = NULL;
>> + else if (size < 0)
>> + return ERR_PTR(size);
>> +
>> + kfree(value);
>> + if (!IS_ERR(acl))
>> + set_cached_acl(inode, type, acl);
>> +
>> + return acl;
>> +}
>> +
>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>> +{
>> + char *name;
>> + void *value = NULL;
>> + size_t size = 0;
>> + int err;
>> +
>> + switch (type) {
>> + case ACL_TYPE_ACCESS:
>> + name = XATTR_NAME_POSIX_ACL_ACCESS;
>> + if (acl) {
>> + err = posix_acl_equiv_mode(acl, &inode->i_mode);
>> + if (err < 0)
>> + return err;
>> + if (err == 0)
>> + acl = NULL;
>> + }
>> + break;
>> +
>> + case ACL_TYPE_DEFAULT:
>> + name = XATTR_NAME_POSIX_ACL_DEFAULT;
>> + if (!S_ISDIR(inode->i_mode))
>> + return acl ? -EACCES : 0;
>> + break;
>> +
>> + default:
>> + BUG();
>> + }
>> +
>> + if (acl) {
>> + value = acl_to_flash(acl, &size, type);
>> + if (IS_ERR(value))
>> + return (int) PTR_ERR(value);
>> + }
>> +
>> + err = ubifs_do_setxattr(inode, name, value, size, 0);
>> + kfree(value);
>> + if (!err)
>> + set_cached_acl(inode, type, acl);
>> + return err;
>> +}
>> +
>> +/*
>> + * Initialize the ACLs of a new inode.
>> + */
>> +int ubifs_init_acl(struct inode *dir, struct inode *inode)
>> +{
>> + struct posix_acl *default_acl, *acl;
>> + int err;
>> +
>> + err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
>> + if (err)
>> + return err;
>> +
>> + if (default_acl) {
>> + mutex_lock(&inode->i_mutex);
>> + err = ubifs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
>> + mutex_unlock(&inode->i_mutex);
>> + posix_acl_release(default_acl);
>> + }
>> +
>> + if (acl) {
>> + if (!err) {
>> + mutex_lock(&inode->i_mutex);
>> + err = ubifs_set_acl(inode, acl, ACL_TYPE_ACCESS);
>> + mutex_unlock(&inode->i_mutex);
>> + }
>> + posix_acl_release(acl);
>> + }
>> +
>> + return err;
>> +}
>> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
>> index 5c27c66..db5dd45 100644
>> --- a/fs/ubifs/dir.c
>> +++ b/fs/ubifs/dir.c
>> @@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
>> goto out_budg;
>> }
>>
>> + err = ubifs_init_acl(dir, inode);
>> + if (err)
>> + goto out_inode;
>> +
>> err = ubifs_init_security(dir, inode, &dentry->d_name);
>> if (err)
>> goto out_inode;
>> @@ -731,6 +735,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
>> goto out_budg;
>> }
>>
>> + err = ubifs_init_acl(dir, inode);
>> + if (err)
>> + goto out_inode;
>> +
>> err = ubifs_init_security(dir, inode, &dentry->d_name);
>> if (err)
>> goto out_inode;
>> @@ -810,6 +818,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
>> goto out_budg;
>> }
>>
>> + err = ubifs_init_acl(dir, inode);
>> + if (err)
>> + goto out_inode;
>> +
>> init_special_inode(inode, inode->i_mode, rdev);
>> inode->i_size = ubifs_inode(inode)->ui_size = devlen;
>> ui = ubifs_inode(inode);
>> @@ -898,6 +910,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
>> ui->data_len = len;
>> inode->i_size = ubifs_inode(inode)->ui_size = len;
>>
>> + err = ubifs_init_acl(dir, inode);
>> + if (err)
>> + goto out_inode;
>> +
>> err = ubifs_init_security(dir, inode, &dentry->d_name);
>> if (err)
>> goto out_inode;
>> @@ -1188,6 +1204,10 @@ const struct inode_operations ubifs_dir_inode_operations = {
>> .getxattr = ubifs_getxattr,
>> .listxattr = ubifs_listxattr,
>> .removexattr = ubifs_removexattr,
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + .get_acl = ubifs_get_acl,
>> + .set_acl = ubifs_set_acl,
>> +#endif
>> };
>>
>> const struct file_operations ubifs_dir_operations = {
>> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
>> index a3dfe2a..74f4c63 100644
>> --- a/fs/ubifs/file.c
>> +++ b/fs/ubifs/file.c
>> @@ -52,6 +52,7 @@
>> #include "ubifs.h"
>> #include <linux/mount.h>
>> #include <linux/slab.h>
>> +#include <linux/posix_acl.h>
>>
>> static int read_block(struct inode *inode, void *addr, unsigned int block,
>> struct ubifs_data_node *dn)
>> @@ -1246,6 +1247,11 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
>> mark_inode_dirty_sync(inode);
>> mutex_unlock(&ui->ui_mutex);
>>
>> + if (attr->ia_valid & ATTR_MODE)
>> + err = posix_acl_chmod(inode, inode->i_mode);
>> + if (err)
>> + return err;
>> +
>> if (release)
>> ubifs_release_budget(c, &req);
>> if (IS_SYNC(inode))
>> @@ -1557,6 +1563,10 @@ const struct inode_operations ubifs_file_inode_operations = {
>> .getxattr = ubifs_getxattr,
>> .listxattr = ubifs_listxattr,
>> .removexattr = ubifs_removexattr,
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + .get_acl = ubifs_get_acl,
>> + .set_acl = ubifs_set_acl,
>> +#endif
>> };
>>
>> const struct inode_operations ubifs_symlink_inode_operations = {
>> @@ -1568,6 +1578,10 @@ const struct inode_operations ubifs_symlink_inode_operations = {
>> .getxattr = ubifs_getxattr,
>> .listxattr = ubifs_listxattr,
>> .removexattr = ubifs_removexattr,
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + .get_acl = ubifs_get_acl,
>> + .set_acl = ubifs_set_acl,
>> +#endif
>> };
>>
>> const struct file_operations ubifs_file_operations = {
>> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
>> index 9547a278..52baad1 100644
>> --- a/fs/ubifs/super.c
>> +++ b/fs/ubifs/super.c
>> @@ -441,6 +441,9 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
>> ubifs_compr_name(c->mount_opts.compr_type));
>> }
>>
>> + if (c->vfs_sb->s_flags & MS_POSIXACL)
>> + seq_printf(s, ",acl");
>> +
>> return 0;
>> }
>>
>> @@ -926,6 +929,8 @@ enum {
>> Opt_chk_data_crc,
>> Opt_no_chk_data_crc,
>> Opt_override_compr,
>> + Opt_acl,
>> + Opt_noacl,
>> Opt_err,
>> };
>>
>> @@ -937,6 +942,8 @@ static const match_table_t tokens = {
>> {Opt_chk_data_crc, "chk_data_crc"},
>> {Opt_no_chk_data_crc, "no_chk_data_crc"},
>> {Opt_override_compr, "compr=%s"},
>> + {Opt_acl, "acl"},
>> + {Opt_noacl, "noacl"},
>> {Opt_err, NULL},
>> };
>>
>> @@ -1037,6 +1044,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
>> c->default_compr = c->mount_opts.compr_type;
>> break;
>> }
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + case Opt_acl:
>> + c->vfs_sb->s_flags |= MS_POSIXACL;
>> + break;
>> + case Opt_noacl:
>> + c->vfs_sb->s_flags &= ~MS_POSIXACL;
>> + break;
>> +#endif
>> default:
>> {
>> unsigned long flag;
>> diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
>> index 62aa1a5..b9ddc8d 100644
>> --- a/fs/ubifs/ubifs.h
>> +++ b/fs/ubifs/ubifs.h
>> @@ -1767,6 +1767,20 @@ int ubifs_removexattr(struct dentry *dentry, const char *name);
>> int ubifs_init_security(struct inode *dentry, struct inode *inode,
>> const struct qstr *qstr);
>>
>> +/* acl.c */
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> +int ubifs_init_acl(struct inode *dir, struct inode *inode);
>> +int ubifs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
>> +struct posix_acl *ubifs_get_acl(struct inode *inode, int type);
>> +#else
>> +static inline int ubifs_init_acl(struct inode *inode, struct inode *dir)
>> +{
>> + return 0;
>> +}
>> +#define ubifs_get_acl NULL
>> +#define ubifs_set_acl NULL
>> +#endif
>> +
>> /* super.c */
>> struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
>>
>> diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
>> index 6534b98..f2556d2 100644
>> --- a/fs/ubifs/xattr.c
>> +++ b/fs/ubifs/xattr.c
>> @@ -52,7 +52,6 @@
>> * in the VFS inode cache. The xentries are cached in the LNC cache (see
>> * tnc.c).
>> *
>> - * ACL support is not implemented.
>> */
>>
>> #include "ubifs.h"
>> @@ -78,6 +77,10 @@ enum {
>> USER_XATTR,
>> TRUSTED_XATTR,
>> SECURITY_XATTR,
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + POSIX_ACL_DEFAULT,
>> + POSIX_ACL_ACCESS,
>> +#endif
>> };
>>
>> static const struct inode_operations empty_iops;
>> @@ -276,6 +279,18 @@ static int check_namespace(const struct qstr *nm)
>> if (nm->name[sizeof(XATTR_SECURITY_PREFIX) - 1] == '\0')
>> return -EINVAL;
>> type = SECURITY_XATTR;
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + } else if (!strncmp(nm->name, XATTR_NAME_POSIX_ACL_DEFAULT,
>> + sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {
>> + if (nm->name[sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1] != '\0')
>> + return -EINVAL;
>> + type = POSIX_ACL_DEFAULT;
>> + } else if (!strncmp(nm->name, XATTR_NAME_POSIX_ACL_ACCESS,
>> + sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1)) {
>> + if (nm->name[sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1] != '\0')
>> + return -EINVAL;
>> + type = POSIX_ACL_ACCESS;
>> +#endif
>> } else
>> return -EOPNOTSUPP;
>>
>> @@ -359,6 +374,9 @@ out_free:
>> int ubifs_setxattr(struct dentry *dentry, const char *name,
>> const void *value, size_t size, int flags)
>> {
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + const struct xattr_handler *handler;
>> +#endif
>> struct qstr nm = QSTR_INIT(name, strlen(name));
>> int type;
>>
>> @@ -369,6 +387,16 @@ int ubifs_setxattr(struct dentry *dentry, const char *name,
>> if (type < 0)
>> return type;
>>
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + if (type == POSIX_ACL_DEFAULT || type == POSIX_ACL_ACCESS) {
>> + if (type == POSIX_ACL_DEFAULT)
>> + handler = &posix_acl_default_xattr_handler;
>> + if (type == POSIX_ACL_ACCESS)
>> + handler = &posix_acl_access_xattr_handler;
>> + return handler->set(dentry, name, value, size, flags,
>> + handler->flags);
>> + }
>> +#endif
>> return ubifs_do_setxattr(d_inode(dentry), name, value, size, flags);
>> }
>>
>> @@ -428,6 +456,9 @@ out_unlock:
>> ssize_t ubifs_getxattr(struct dentry *dentry, const char *name,
>> void *value, size_t size)
>> {
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + const struct xattr_handler *handler;
>> +#endif
>> struct qstr nm = QSTR_INIT(name, strlen(name));
>> int type;
>>
>> @@ -438,6 +469,16 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name,
>> if (type < 0)
>> return type;
>>
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + if (type == POSIX_ACL_DEFAULT || type == POSIX_ACL_ACCESS) {
>> + if (type == POSIX_ACL_DEFAULT)
>> + handler = &posix_acl_default_xattr_handler;
>> + if (type == POSIX_ACL_ACCESS)
>> + handler = &posix_acl_access_xattr_handler;
>> + return handler->get(dentry, name, value, size,
>> + handler->flags);
>> + }
>> +#endif
>> return ubifs_do_getxattr(d_inode(dentry), name, value, size);
>> }
>>
>> @@ -547,20 +588,33 @@ out_cancel:
>>
>> int ubifs_removexattr(struct dentry *dentry, const char *name)
>> {
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + const struct xattr_handler *handler;
>> +#endif
>> struct inode *inode, *host = d_inode(dentry);
>> struct ubifs_info *c = host->i_sb->s_fs_info;
>> struct qstr nm = QSTR_INIT(name, strlen(name));
>> struct ubifs_dent_node *xent;
>> union ubifs_key key;
>> - int err;
>> + int type, err;
>>
>> dbg_gen("xattr '%s', ino %lu ('%pd')", name,
>> host->i_ino, dentry);
>> ubifs_assert(mutex_is_locked(&host->i_mutex));
>>
>> - err = check_namespace(&nm);
>> - if (err < 0)
>> - return err;
>> + type = check_namespace(&nm);
>> + if (type < 0)
>> + return type;
>> +
>> +#ifdef CONFIG_UBIFS_FS_POSIX_ACL
>> + if (type == POSIX_ACL_DEFAULT || type == POSIX_ACL_ACCESS) {
>> + if (type == POSIX_ACL_DEFAULT)
>> + handler = &posix_acl_default_xattr_handler;
>> + if (type == POSIX_ACL_ACCESS)
>> + handler = &posix_acl_access_xattr_handler;
>> + return handler->set(dentry, name, NULL, 0, 0, handler->flags);
>> + }
>> +#endif
>>
>> xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
>> if (!xent)
>>
>
>
> .
>
More information about the linux-mtd
mailing list