struct posix_acl *gfs2_get_acl(struct inode *inode, int type) { struct gfs2_inode *ip = GFS2_I(inode); struct posix_acl *acl; const char *name; char *data; int len; if (!ip->i_eattr) return NULL; acl = get_cached_acl(&ip->i_inode, type); if (acl != ACL_NOT_CACHED) return acl; name = gfs2_acl_name(type); if (name == NULL) return ERR_PTR(-EINVAL); len = gfs2_xattr_acl_get(ip, name, &data); if (len < 0) return ERR_PTR(len); if (len == 0) return NULL; acl = posix_acl_from_xattr(data, len); kfree(data); return acl; }
/** * generic_acl_init - Take care of acl inheritance at @inode create time * * Files created inside a directory with a default ACL inherit the * directory's default ACL. */ int generic_acl_init(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; mode_t mode = inode->i_mode; int error; inode->i_mode = mode & ~current_umask(); if (!S_ISLNK(inode->i_mode)) acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); if (acl) { struct posix_acl *clone; if (S_ISDIR(inode->i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); clone = posix_acl_clone(acl, GFP_KERNEL); error = -ENOMEM; if (!clone) goto cleanup; error = posix_acl_create_masq(clone, &mode); if (error >= 0) { inode->i_mode = mode; if (error > 0) set_cached_acl(inode, ACL_TYPE_ACCESS, clone); } posix_acl_release(clone); } error = 0; cleanup: posix_acl_release(acl); return error; }
struct posix_acl *get_acl(struct inode *inode, int type) { struct posix_acl *acl; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; if (!IS_POSIXACL(inode)) return NULL; /* * A filesystem can force a ACL callback by just never filling the * ACL cache. But normally you'd fill the cache either at inode * instantiation time, or on the first ->get_acl call. * * If the filesystem doesn't have a get_acl() function at all, we'll * just create the negative cache entry. */ if (!inode->i_op->get_acl) { set_cached_acl(inode, type, NULL); return NULL; } return inode->i_op->get_acl(inode, type); }
static size_t generic_acl_list(struct dentry *dentry, char *list, size_t list_size, const char *name, size_t name_len, int type) { struct posix_acl *acl; const char *xname; size_t size; acl = get_cached_acl(dentry->d_inode, type); if (!acl) return 0; posix_acl_release(acl); switch (type) { case ACL_TYPE_ACCESS: xname = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: xname = POSIX_ACL_XATTR_DEFAULT; break; default: return 0; } size = strlen(xname) + 1; if (list && size <= list_size) memcpy(list, xname, size); return size; }
struct posix_acl * xfs_get_acl(struct inode *inode, int type) { struct xfs_inode *ip = XFS_I(inode); struct posix_acl *acl; struct xfs_acl *xfs_acl; int len = sizeof(struct xfs_acl); unsigned char *ea_name; int error; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch (type) { case ACL_TYPE_ACCESS: ea_name = SGI_ACL_FILE; break; case ACL_TYPE_DEFAULT: ea_name = SGI_ACL_DEFAULT; break; default: BUG(); } /* * If we have a cached ACLs value just return it, not need to * go out to the disk. */ xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); if (!xfs_acl) return ERR_PTR(-ENOMEM); error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, &len, ATTR_ROOT); if (error) { /* * If the attribute doesn't exist make sure we have a negative * cache entry, for any other error assume it is transient and * leave the cache entry as ACL_NOT_CACHED. */ if (error == -ENOATTR) { acl = NULL; goto out_update_cache; } goto out; } acl = xfs_acl_from_disk(xfs_acl); if (IS_ERR(acl)) goto out; out_update_cache: set_cached_acl(inode, type, acl); out: kfree(xfs_acl); return acl; }
struct posix_acl * zpl_get_acl(struct inode *ip, int type) { struct posix_acl *acl; void *value = NULL; char *name; int size; /* * As of Linux 3.14, the kernel get_acl will check this for us. * Also as of Linux 4.7, comparing against ACL_NOT_CACHED is wrong * as the kernel get_acl will set it to temporary sentinel value. */ #ifndef HAVE_KERNEL_GET_ACL_HANDLE_CACHE acl = get_cached_acl(ip, type); if (acl != ACL_NOT_CACHED) return (acl); #endif 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: return (ERR_PTR(-EINVAL)); } size = zpl_xattr_get(ip, name, NULL, 0); if (size > 0) { value = kmem_alloc(size, KM_SLEEP); size = zpl_xattr_get(ip, name, value, size); } if (size > 0) { acl = zpl_acl_from_xattr(value, size); } else if (size == -ENODATA || size == -ENOSYS) { acl = NULL; } else { acl = ERR_PTR(-EIO); } if (size > 0) kmem_free(value, size); /* As of Linux 4.7, the kernel get_acl will set this for us */ #ifndef HAVE_KERNEL_GET_ACL_HANDLE_CACHE if (!IS_ERR(acl)) zpl_set_cached_acl(ip, type, acl); #endif return (acl); }
static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) { struct posix_acl *acl; /* * 9p Always cache the acl value when * instantiating the inode (v9fs_inode_from_fid) */ acl = get_cached_acl(inode, type); BUG_ON(is_uncached_acl(acl)); return acl; }
int generic_check_acl(struct inode *inode, int mask) { struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { int error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); return error; } return -EAGAIN; }
static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode, int type) { struct ceph_inode_info *ci = ceph_inode(inode); struct posix_acl *acl = ACL_NOT_CACHED; spin_lock(&ci->i_ceph_lock); if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) acl = get_cached_acl(inode, type); spin_unlock(&ci->i_ceph_lock); return acl; }
/* * Inode operation get_posix_acl(). * * inode->i_mutex: down * BKL held [before 2.5.x] */ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) { char *name, *value; struct posix_acl *acl; int size; int retval; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; break; default: BUG(); } size = reiserfs_xattr_get(inode, name, NULL, 0); if (size < 0) { if (size == -ENODATA || size == -ENOSYS) { set_cached_acl(inode, type, NULL); return NULL; } return ERR_PTR(size); } value = kmalloc(size, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); retval = reiserfs_xattr_get(inode, name, value, size); if (retval == -ENODATA || retval == -ENOSYS) { /* This shouldn't actually happen as it should have been caught above.. but just in case */ acl = NULL; } else if (retval < 0) { acl = ERR_PTR(retval); } else { acl = posix_acl_from_disk(value, retval); } if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); kfree(value); return acl; }
struct posix_acl *btrfs_get_acl(struct inode *inode, int type) { int size; const char *name; char *value = NULL; struct posix_acl *acl; if (!IS_POSIXACL(inode)) return NULL; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; break; default: BUG(); } size = __btrfs_getxattr(inode, name, "", 0); if (size > 0) { value = kzalloc(size, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); size = __btrfs_getxattr(inode, name, value, size); if (size > 0) { acl = posix_acl_from_xattr(value, size); if (IS_ERR(acl)) { kfree(value); return acl; } set_cached_acl(inode, type, acl); } kfree(value); } else if (size == -ENOENT || size == -ENODATA || size == 0) { /* FIXME, who returns -ENOENT? I think nobody */ acl = NULL; set_cached_acl(inode, type, acl); } else { acl = ERR_PTR(-EIO); } return acl; }
struct posix_acl * zpl_get_acl(struct inode *ip, int type) { struct posix_acl *acl; void *value = NULL; char *name; int size; #ifdef HAVE_POSIX_ACL_CACHING acl = get_cached_acl(ip, type); if (acl != ACL_NOT_CACHED) return (acl); #endif /* HAVE_POSIX_ACL_CACHING */ switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; break; default: return ERR_PTR(-EINVAL); } size = zpl_xattr_get(ip, name, NULL, 0); if (size > 0) { value = kmem_alloc(size, KM_PUSHPAGE); size = zpl_xattr_get(ip, name, value, size); } if (size > 0) { acl = zpl_acl_from_xattr(value, size); } else if (size == -ENODATA || size == -ENOSYS) { acl = NULL; } else { acl = ERR_PTR(-EIO); } if (size > 0) kmem_free(value, size); if (!IS_ERR(acl)) zpl_set_cached_acl(ip, type, acl); return (acl); }
/* * Inode operation get_posix_acl(). * * inode->i_mutex: don't care */ static struct posix_acl * ext3_get_acl(struct inode *inode, int type) { int name_index; char *value = NULL; struct posix_acl *acl; int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) return NULL; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch (type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; break; default: BUG(); } retval = ext3_xattr_get(inode, name_index, "", NULL, 0); if (retval > 0) { value = kmalloc(retval, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); retval = ext3_xattr_get(inode, name_index, "", value, retval); } if (retval > 0) acl = ext3_acl_from_disk(value, retval); else if (retval == -ENODATA || retval == -ENOSYS) acl = NULL; else acl = ERR_PTR(retval); kfree(value); if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); return acl; }
int generic_check_acl(struct inode *inode, int mask, unsigned int flags) { if (flags & IPERM_FLAG_RCU) { if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) return -ECHILD; } else { struct posix_acl *acl; acl = get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { int error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); return error; } } return -EAGAIN; }
/** * generic_acl_chmod - change the access acl of @inode upon chmod() * * A chmod also changes the permissions of the owner, group/mask, and * other ACL entries. */ int generic_acl_chmod(struct inode *inode) { struct posix_acl *acl; int error = 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; acl = get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); if (error) return error; set_cached_acl(inode, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); } return error; }
static int generic_acl_get(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { struct posix_acl *acl; int error; if (strcmp(name, "") != 0) return -EINVAL; acl = get_cached_acl(dentry->d_inode, type); if (!acl) return -ENODATA; error = posix_acl_to_xattr(acl, buffer, size); posix_acl_release(acl); return error; }
static struct posix_acl *jfs_get_acl(struct inode *inode, int type) { struct posix_acl *acl; char *ea_name; int size; char *value = NULL; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch(type) { case ACL_TYPE_ACCESS: ea_name = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: ea_name = POSIX_ACL_XATTR_DEFAULT; break; default: return ERR_PTR(-EINVAL); } size = __jfs_getxattr(inode, ea_name, NULL, 0); if (size > 0) { value = kmalloc(size, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); size = __jfs_getxattr(inode, ea_name, value, size); } if (size < 0) { if (size == -ENODATA) acl = NULL; else acl = ERR_PTR(size); } else { acl = posix_acl_from_xattr(value, size); } kfree(value); if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); return acl; }
/** * generic_acl_chmod - change the access acl of @inode upon chmod() * * A chmod also changes the permissions of the owner, group/mask, and * other ACL entries. */ int generic_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int error = 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; acl = get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { clone = posix_acl_clone(acl, GFP_KERNEL); posix_acl_release(acl); if (!clone) return -ENOMEM; error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) set_cached_acl(inode, ACL_TYPE_ACCESS, clone); posix_acl_release(clone); } return error; }
struct posix_acl *f2fs_get_acl(struct inode *inode, int type) { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; void *value = NULL; struct posix_acl *acl; int retval; if (!test_opt(sbi, POSIX_ACL)) return NULL; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; if (type == ACL_TYPE_ACCESS) name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; retval = f2fs_getxattr(inode, name_index, "", NULL, 0); if (retval > 0) { value = kmalloc(retval, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); retval = f2fs_getxattr(inode, name_index, "", value, retval); } if (retval < 0) { if (retval == -ENODATA) acl = NULL; else acl = ERR_PTR(retval); } else { acl = f2fs_acl_from_disk(value, retval); } kfree(value); if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); return acl; }
static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) { struct posix_acl *acl; char *value = NULL; int rc, xprefix; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: xprefix = JFFS2_XPREFIX_ACL_DEFAULT; break; default: BUG(); } rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); if (rc > 0) { value = kmalloc(rc, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); } if (rc > 0) { acl = jffs2_acl_from_medium(value, rc); } else if (rc == -ENODATA || rc == -ENOSYS) { acl = NULL; } else { acl = ERR_PTR(rc); } if (value) kfree(value); if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); return acl; }
/** * generic_acl_init - Take care of acl inheritance at @inode create time * * Files created inside a directory with a default ACL inherit the * directory's default ACL. */ int generic_acl_init(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; int error; if (!S_ISLNK(inode->i_mode)) acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); if (acl) { if (S_ISDIR(inode->i_mode)) set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); if (error < 0) return error; if (error > 0) set_cached_acl(inode, ACL_TYPE_ACCESS, acl); } else { inode->i_mode &= ~current_umask(); } error = 0; posix_acl_release(acl); return error; }
struct posix_acl *get_acl(struct inode *inode, int type) { void *sentinel; struct posix_acl **p; struct posix_acl *acl; /* * The sentinel is used to detect when another operation like * set_cached_acl() or forget_cached_acl() races with get_acl(). * It is guaranteed that is_uncached_acl(sentinel) is true. */ acl = get_cached_acl(inode, type); if (!is_uncached_acl(acl)) return acl; if (!IS_POSIXACL(inode)) return NULL; sentinel = uncached_acl_sentinel(current); p = acl_by_type(inode, type); /* * If the ACL isn't being read yet, set our sentinel. Otherwise, the * current value of the ACL will not be ACL_NOT_CACHED and so our own * sentinel will not be set; another task will update the cache. We * could wait for that other task to complete its job, but it's easier * to just call ->get_acl to fetch the ACL ourself. (This is going to * be an unlikely race.) */ if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) /* fall through */ ; /* * Normally, the ACL returned by ->get_acl will be cached. * A filesystem can prevent that by calling * forget_cached_acl(inode, type) in ->get_acl. * * If the filesystem doesn't have a get_acl() function at all, we'll * just create the negative cache entry. */ if (!inode->i_op->get_acl) { set_cached_acl(inode, type, NULL); return NULL; } acl = inode->i_op->get_acl(inode, type); if (IS_ERR(acl)) { /* * Remove our sentinel so that we don't block future attempts * to cache the ACL. */ cmpxchg(p, sentinel, ACL_NOT_CACHED); return acl; } /* * Cache the result, but only if our sentinel is still in place. */ posix_acl_dup(acl); if (unlikely(cmpxchg(p, sentinel, acl) != sentinel)) posix_acl_release(acl); return acl; }