static int ll_getxattr_common(struct inode *inode, const char *name, void *buffer, size_t size, __u64 valid) { struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *req = NULL; struct mdt_body *body; int xattr_type, rc; void *xdata; struct rmtacl_ctl_entry *rce = NULL; struct ll_inode_info *lli = ll_i2info(inode); CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino, inode->i_generation, inode); /* listxattr have slightly different behavior from of ext3: * without 'user_xattr' ext3 will list all xattr names but * filtered out "^user..*"; we list them all for simplicity. */ if (!name) { xattr_type = XATTR_OTHER_T; goto do_getxattr; } xattr_type = get_xattr_type(name); rc = xattr_type_filter(sbi, xattr_type); if (rc) return rc; /* b15587: ignore security.capability xattr for now */ if ((xattr_type == XATTR_SECURITY_T && strcmp(name, "security.capability") == 0)) return -ENODATA; /* LU-549: Disable security.selinux when selinux is disabled */ if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() && strcmp(name, "security.selinux") == 0) return -EOPNOTSUPP; #ifdef CONFIG_FS_POSIX_ACL if (sbi->ll_flags & LL_SBI_RMT_CLIENT && (xattr_type == XATTR_ACL_ACCESS_T || xattr_type == XATTR_ACL_DEFAULT_T)) { rce = rct_search(&sbi->ll_rct, current_pid()); if (!rce || (rce->rce_ops != RMT_LSETFACL && rce->rce_ops != RMT_LGETFACL && rce->rce_ops != RMT_RSETFACL && rce->rce_ops != RMT_RGETFACL)) return -EOPNOTSUPP; } /* posix acl is under protection of LOOKUP lock. when calling to this, * we just have path resolution to the target inode, so we have great * chance that cached ACL is uptodate. */ if (xattr_type == XATTR_ACL_ACCESS_T && !(sbi->ll_flags & LL_SBI_RMT_CLIENT)) { struct posix_acl *acl; spin_lock(&lli->lli_lock); acl = posix_acl_dup(lli->lli_posix_acl); spin_unlock(&lli->lli_lock); if (!acl) return -ENODATA; rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); posix_acl_release(acl); return rc; } if (xattr_type == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode)) return -ENODATA; #endif do_getxattr: if (sbi->ll_xattr_cache_enabled && xattr_type != XATTR_ACL_ACCESS_T) { rc = ll_xattr_cache_get(inode, name, buffer, size, valid); if (rc == -EAGAIN) goto getxattr_nocache; if (rc < 0) goto out_xattr; /* Add "system.posix_acl_access" to the list */ if (lli->lli_posix_acl && valid & OBD_MD_FLXATTRLS) { if (size == 0) { rc += sizeof(XATTR_NAME_ACL_ACCESS); } else if (size - rc >= sizeof(XATTR_NAME_ACL_ACCESS)) { memcpy(buffer + rc, XATTR_NAME_ACL_ACCESS, sizeof(XATTR_NAME_ACL_ACCESS)); rc += sizeof(XATTR_NAME_ACL_ACCESS); } else { rc = -ERANGE; goto out_xattr; } } } else { getxattr_nocache: rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), valid | (rce ? rce_ops2valid(rce->rce_ops) : 0), name, NULL, 0, size, 0, &req); if (rc < 0) goto out_xattr; body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); LASSERT(body); /* only detect the xattr size */ if (size == 0) { rc = body->eadatasize; goto out; } if (size < body->eadatasize) { CERROR("server bug: replied size %u > %u\n", body->eadatasize, (int)size); rc = -ERANGE; goto out; } if (body->eadatasize == 0) { rc = -ENODATA; goto out; } /* do not need swab xattr data */ xdata = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA, body->eadatasize); if (!xdata) { rc = -EFAULT; goto out; } memcpy(buffer, xdata, body->eadatasize); rc = body->eadatasize; } #ifdef CONFIG_FS_POSIX_ACL if (rce && rce->rce_ops == RMT_LSETFACL) { ext_acl_xattr_header *acl; acl = lustre_posix_acl_xattr_2ext( (posix_acl_xattr_header *)buffer, rc); if (IS_ERR(acl)) { rc = PTR_ERR(acl); goto out; } rc = ee_add(&sbi->ll_et, current_pid(), ll_inode2fid(inode), xattr_type, acl); if (unlikely(rc < 0)) { lustre_ext_acl_xattr_free(acl); goto out; } } #endif out_xattr: if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) { LCONSOLE_INFO( "%s: disabling user_xattr feature because it is not supported on the server: rc = %d\n", ll_get_fsname(inode->i_sb, NULL, 0), rc); sbi->ll_flags &= ~LL_SBI_USER_XATTR; } out: ptlrpc_req_finished(req); return rc; }
/* * Inode operation set_posix_acl(). * * inode->i_mutex: down * BKL held [before 2.5.x] */ static int reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) { char *name; void *value = NULL; struct posix_acl **p_acl; size_t size; int error; struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; p_acl = &reiserfs_i->i_acl_access; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); if (error < 0) return error; else { inode->i_mode = mode; if (error == 0) acl = NULL; } } break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; p_acl = &reiserfs_i->i_acl_default; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = posix_acl_to_disk(acl, &size); if (IS_ERR(value)) return (int)PTR_ERR(value); error = reiserfs_xattr_set(inode, name, value, size, 0); } else { error = reiserfs_xattr_del(inode, name); if (error == -ENODATA) { /* This may seem odd here, but it means that the ACL was set * with a value representable with mode bits. If there was * an ACL before, reiserfs_xattr_del already dirtied the inode. */ mark_inode_dirty(inode); error = 0; } } kfree(value); if (!error) { /* Release the old one */ if (!IS_ERR(*p_acl) && *p_acl) posix_acl_release(*p_acl); if (acl == NULL) *p_acl = ERR_PTR(-ENODATA); else *p_acl = posix_acl_dup(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; }