Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2007 Red Hat.  All rights reserved.
0004  */
0005 
0006 #include <linux/fs.h>
0007 #include <linux/string.h>
0008 #include <linux/xattr.h>
0009 #include <linux/posix_acl_xattr.h>
0010 #include <linux/posix_acl.h>
0011 #include <linux/sched.h>
0012 #include <linux/sched/mm.h>
0013 #include <linux/slab.h>
0014 
0015 #include "ctree.h"
0016 #include "btrfs_inode.h"
0017 #include "xattr.h"
0018 
0019 struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
0020 {
0021     int size;
0022     const char *name;
0023     char *value = NULL;
0024     struct posix_acl *acl;
0025 
0026     if (rcu)
0027         return ERR_PTR(-ECHILD);
0028 
0029     switch (type) {
0030     case ACL_TYPE_ACCESS:
0031         name = XATTR_NAME_POSIX_ACL_ACCESS;
0032         break;
0033     case ACL_TYPE_DEFAULT:
0034         name = XATTR_NAME_POSIX_ACL_DEFAULT;
0035         break;
0036     default:
0037         return ERR_PTR(-EINVAL);
0038     }
0039 
0040     size = btrfs_getxattr(inode, name, NULL, 0);
0041     if (size > 0) {
0042         value = kzalloc(size, GFP_KERNEL);
0043         if (!value)
0044             return ERR_PTR(-ENOMEM);
0045         size = btrfs_getxattr(inode, name, value, size);
0046     }
0047     if (size > 0)
0048         acl = posix_acl_from_xattr(&init_user_ns, value, size);
0049     else if (size == -ENODATA || size == 0)
0050         acl = NULL;
0051     else
0052         acl = ERR_PTR(size);
0053     kfree(value);
0054 
0055     return acl;
0056 }
0057 
0058 int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
0059             struct posix_acl *acl, int type)
0060 {
0061     int ret, size = 0;
0062     const char *name;
0063     char *value = NULL;
0064 
0065     switch (type) {
0066     case ACL_TYPE_ACCESS:
0067         name = XATTR_NAME_POSIX_ACL_ACCESS;
0068         break;
0069     case ACL_TYPE_DEFAULT:
0070         if (!S_ISDIR(inode->i_mode))
0071             return acl ? -EINVAL : 0;
0072         name = XATTR_NAME_POSIX_ACL_DEFAULT;
0073         break;
0074     default:
0075         return -EINVAL;
0076     }
0077 
0078     if (acl) {
0079         unsigned int nofs_flag;
0080 
0081         size = posix_acl_xattr_size(acl->a_count);
0082         /*
0083          * We're holding a transaction handle, so use a NOFS memory
0084          * allocation context to avoid deadlock if reclaim happens.
0085          */
0086         nofs_flag = memalloc_nofs_save();
0087         value = kmalloc(size, GFP_KERNEL);
0088         memalloc_nofs_restore(nofs_flag);
0089         if (!value) {
0090             ret = -ENOMEM;
0091             goto out;
0092         }
0093 
0094         ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
0095         if (ret < 0)
0096             goto out;
0097     }
0098 
0099     if (trans)
0100         ret = btrfs_setxattr(trans, inode, name, value, size, 0);
0101     else
0102         ret = btrfs_setxattr_trans(inode, name, value, size, 0);
0103 
0104 out:
0105     kfree(value);
0106 
0107     if (!ret)
0108         set_cached_acl(inode, type, acl);
0109 
0110     return ret;
0111 }
0112 
0113 int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
0114           struct posix_acl *acl, int type)
0115 {
0116     int ret;
0117     umode_t old_mode = inode->i_mode;
0118 
0119     if (type == ACL_TYPE_ACCESS && acl) {
0120         ret = posix_acl_update_mode(mnt_userns, inode,
0121                         &inode->i_mode, &acl);
0122         if (ret)
0123             return ret;
0124     }
0125     ret = __btrfs_set_acl(NULL, inode, acl, type);
0126     if (ret)
0127         inode->i_mode = old_mode;
0128     return ret;
0129 }