1b7fa0554SAndreas Gruenbacher #include <linux/fs.h> 25a0e3ad6STejun Heo #include <linux/gfp.h> 3b7fa0554SAndreas Gruenbacher #include <linux/nfs.h> 4b7fa0554SAndreas Gruenbacher #include <linux/nfs3.h> 5b7fa0554SAndreas Gruenbacher #include <linux/nfs_fs.h> 6334a13ecSChristoph Hellwig #include <linux/posix_acl_xattr.h> 7b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h> 8b7fa0554SAndreas Gruenbacher 9f41f7418STrond Myklebust #include "internal.h" 10f41f7418STrond Myklebust 11b7fa0554SAndreas Gruenbacher #define NFSDBG_FACILITY NFSDBG_PROC 12b7fa0554SAndreas Gruenbacher 13b7fa0554SAndreas Gruenbacher ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) 14b7fa0554SAndreas Gruenbacher { 15b7fa0554SAndreas Gruenbacher struct inode *inode = dentry->d_inode; 16b7fa0554SAndreas Gruenbacher struct posix_acl *acl; 17b7fa0554SAndreas Gruenbacher int pos=0, len=0; 18b7fa0554SAndreas Gruenbacher 19b7fa0554SAndreas Gruenbacher # define output(s) do { \ 20b7fa0554SAndreas Gruenbacher if (pos + sizeof(s) <= size) { \ 21b7fa0554SAndreas Gruenbacher memcpy(buffer + pos, s, sizeof(s)); \ 22b7fa0554SAndreas Gruenbacher pos += sizeof(s); \ 23b7fa0554SAndreas Gruenbacher } \ 24b7fa0554SAndreas Gruenbacher len += sizeof(s); \ 25b7fa0554SAndreas Gruenbacher } while(0) 26b7fa0554SAndreas Gruenbacher 27b7fa0554SAndreas Gruenbacher acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); 28b7fa0554SAndreas Gruenbacher if (IS_ERR(acl)) 29b7fa0554SAndreas Gruenbacher return PTR_ERR(acl); 30b7fa0554SAndreas Gruenbacher if (acl) { 31b7fa0554SAndreas Gruenbacher output("system.posix_acl_access"); 32b7fa0554SAndreas Gruenbacher posix_acl_release(acl); 33b7fa0554SAndreas Gruenbacher } 34b7fa0554SAndreas Gruenbacher 35b7fa0554SAndreas Gruenbacher if (S_ISDIR(inode->i_mode)) { 36b7fa0554SAndreas Gruenbacher acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); 37b7fa0554SAndreas Gruenbacher if (IS_ERR(acl)) 38b7fa0554SAndreas Gruenbacher return PTR_ERR(acl); 39b7fa0554SAndreas Gruenbacher if (acl) { 40b7fa0554SAndreas Gruenbacher output("system.posix_acl_default"); 41b7fa0554SAndreas Gruenbacher posix_acl_release(acl); 42b7fa0554SAndreas Gruenbacher } 43b7fa0554SAndreas Gruenbacher } 44b7fa0554SAndreas Gruenbacher 45b7fa0554SAndreas Gruenbacher # undef output 46b7fa0554SAndreas Gruenbacher 47b7fa0554SAndreas Gruenbacher if (!buffer || len <= size) 48b7fa0554SAndreas Gruenbacher return len; 49b7fa0554SAndreas Gruenbacher return -ERANGE; 50b7fa0554SAndreas Gruenbacher } 51b7fa0554SAndreas Gruenbacher 52b7fa0554SAndreas Gruenbacher ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, 53b7fa0554SAndreas Gruenbacher void *buffer, size_t size) 54b7fa0554SAndreas Gruenbacher { 55b7fa0554SAndreas Gruenbacher struct inode *inode = dentry->d_inode; 56b7fa0554SAndreas Gruenbacher struct posix_acl *acl; 57b7fa0554SAndreas Gruenbacher int type, error = 0; 58b7fa0554SAndreas Gruenbacher 59334a13ecSChristoph Hellwig if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) 60b7fa0554SAndreas Gruenbacher type = ACL_TYPE_ACCESS; 61334a13ecSChristoph Hellwig else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) 62b7fa0554SAndreas Gruenbacher type = ACL_TYPE_DEFAULT; 63b7fa0554SAndreas Gruenbacher else 64b7fa0554SAndreas Gruenbacher return -EOPNOTSUPP; 65b7fa0554SAndreas Gruenbacher 66b7fa0554SAndreas Gruenbacher acl = nfs3_proc_getacl(inode, type); 67b7fa0554SAndreas Gruenbacher if (IS_ERR(acl)) 68b7fa0554SAndreas Gruenbacher return PTR_ERR(acl); 69b7fa0554SAndreas Gruenbacher else if (acl) { 70b7fa0554SAndreas Gruenbacher if (type == ACL_TYPE_ACCESS && acl->a_count == 0) 71b7fa0554SAndreas Gruenbacher error = -ENODATA; 72b7fa0554SAndreas Gruenbacher else 73b7fa0554SAndreas Gruenbacher error = posix_acl_to_xattr(acl, buffer, size); 74b7fa0554SAndreas Gruenbacher posix_acl_release(acl); 75b7fa0554SAndreas Gruenbacher } else 76b7fa0554SAndreas Gruenbacher error = -ENODATA; 77b7fa0554SAndreas Gruenbacher 78b7fa0554SAndreas Gruenbacher return error; 79b7fa0554SAndreas Gruenbacher } 80b7fa0554SAndreas Gruenbacher 81b7fa0554SAndreas Gruenbacher int nfs3_setxattr(struct dentry *dentry, const char *name, 82b7fa0554SAndreas Gruenbacher const void *value, size_t size, int flags) 83b7fa0554SAndreas Gruenbacher { 84b7fa0554SAndreas Gruenbacher struct inode *inode = dentry->d_inode; 85b7fa0554SAndreas Gruenbacher struct posix_acl *acl; 86b7fa0554SAndreas Gruenbacher int type, error; 87b7fa0554SAndreas Gruenbacher 88334a13ecSChristoph Hellwig if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) 89b7fa0554SAndreas Gruenbacher type = ACL_TYPE_ACCESS; 90334a13ecSChristoph Hellwig else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) 91b7fa0554SAndreas Gruenbacher type = ACL_TYPE_DEFAULT; 92b7fa0554SAndreas Gruenbacher else 93b7fa0554SAndreas Gruenbacher return -EOPNOTSUPP; 94b7fa0554SAndreas Gruenbacher 95b7fa0554SAndreas Gruenbacher acl = posix_acl_from_xattr(value, size); 96b7fa0554SAndreas Gruenbacher if (IS_ERR(acl)) 97b7fa0554SAndreas Gruenbacher return PTR_ERR(acl); 98b7fa0554SAndreas Gruenbacher error = nfs3_proc_setacl(inode, type, acl); 99b7fa0554SAndreas Gruenbacher posix_acl_release(acl); 100b7fa0554SAndreas Gruenbacher 101b7fa0554SAndreas Gruenbacher return error; 102b7fa0554SAndreas Gruenbacher } 103b7fa0554SAndreas Gruenbacher 104b7fa0554SAndreas Gruenbacher int nfs3_removexattr(struct dentry *dentry, const char *name) 105b7fa0554SAndreas Gruenbacher { 106b7fa0554SAndreas Gruenbacher struct inode *inode = dentry->d_inode; 107b7fa0554SAndreas Gruenbacher int type; 108b7fa0554SAndreas Gruenbacher 109334a13ecSChristoph Hellwig if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) 110b7fa0554SAndreas Gruenbacher type = ACL_TYPE_ACCESS; 111334a13ecSChristoph Hellwig else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) 112b7fa0554SAndreas Gruenbacher type = ACL_TYPE_DEFAULT; 113b7fa0554SAndreas Gruenbacher else 114b7fa0554SAndreas Gruenbacher return -EOPNOTSUPP; 115b7fa0554SAndreas Gruenbacher 116b7fa0554SAndreas Gruenbacher return nfs3_proc_setacl(inode, type, NULL); 117b7fa0554SAndreas Gruenbacher } 118b7fa0554SAndreas Gruenbacher 1195c6a9f7dSAndreas Gruenbacher static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) 1205c6a9f7dSAndreas Gruenbacher { 121458818edSTrond Myklebust if (!IS_ERR(nfsi->acl_access)) { 1225c6a9f7dSAndreas Gruenbacher posix_acl_release(nfsi->acl_access); 1235c6a9f7dSAndreas Gruenbacher nfsi->acl_access = ERR_PTR(-EAGAIN); 1245c6a9f7dSAndreas Gruenbacher } 125458818edSTrond Myklebust if (!IS_ERR(nfsi->acl_default)) { 1265c6a9f7dSAndreas Gruenbacher posix_acl_release(nfsi->acl_default); 1275c6a9f7dSAndreas Gruenbacher nfsi->acl_default = ERR_PTR(-EAGAIN); 1285c6a9f7dSAndreas Gruenbacher } 1295c6a9f7dSAndreas Gruenbacher } 1305c6a9f7dSAndreas Gruenbacher 1315c6a9f7dSAndreas Gruenbacher void nfs3_forget_cached_acls(struct inode *inode) 1325c6a9f7dSAndreas Gruenbacher { 1335c6a9f7dSAndreas Gruenbacher dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, 1345c6a9f7dSAndreas Gruenbacher inode->i_ino); 1355c6a9f7dSAndreas Gruenbacher spin_lock(&inode->i_lock); 1365c6a9f7dSAndreas Gruenbacher __nfs3_forget_cached_acls(NFS_I(inode)); 1375c6a9f7dSAndreas Gruenbacher spin_unlock(&inode->i_lock); 1385c6a9f7dSAndreas Gruenbacher } 1395c6a9f7dSAndreas Gruenbacher 1405c6a9f7dSAndreas Gruenbacher static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) 1415c6a9f7dSAndreas Gruenbacher { 1425c6a9f7dSAndreas Gruenbacher struct nfs_inode *nfsi = NFS_I(inode); 143458818edSTrond Myklebust struct posix_acl *acl = ERR_PTR(-EINVAL); 1445c6a9f7dSAndreas Gruenbacher 1455c6a9f7dSAndreas Gruenbacher spin_lock(&inode->i_lock); 1465c6a9f7dSAndreas Gruenbacher switch(type) { 1475c6a9f7dSAndreas Gruenbacher case ACL_TYPE_ACCESS: 1485c6a9f7dSAndreas Gruenbacher acl = nfsi->acl_access; 1495c6a9f7dSAndreas Gruenbacher break; 1505c6a9f7dSAndreas Gruenbacher 1515c6a9f7dSAndreas Gruenbacher case ACL_TYPE_DEFAULT: 1525c6a9f7dSAndreas Gruenbacher acl = nfsi->acl_default; 1535c6a9f7dSAndreas Gruenbacher break; 1545c6a9f7dSAndreas Gruenbacher 1555c6a9f7dSAndreas Gruenbacher default: 156458818edSTrond Myklebust goto out; 1575c6a9f7dSAndreas Gruenbacher } 158458818edSTrond Myklebust if (IS_ERR(acl)) 1595c6a9f7dSAndreas Gruenbacher acl = ERR_PTR(-EAGAIN); 1605c6a9f7dSAndreas Gruenbacher else 1615c6a9f7dSAndreas Gruenbacher acl = posix_acl_dup(acl); 162458818edSTrond Myklebust out: 1635c6a9f7dSAndreas Gruenbacher spin_unlock(&inode->i_lock); 1645c6a9f7dSAndreas Gruenbacher dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, 1655c6a9f7dSAndreas Gruenbacher inode->i_ino, type, acl); 1665c6a9f7dSAndreas Gruenbacher return acl; 1675c6a9f7dSAndreas Gruenbacher } 1685c6a9f7dSAndreas Gruenbacher 1695c6a9f7dSAndreas Gruenbacher static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, 1705c6a9f7dSAndreas Gruenbacher struct posix_acl *dfacl) 1715c6a9f7dSAndreas Gruenbacher { 1725c6a9f7dSAndreas Gruenbacher struct nfs_inode *nfsi = NFS_I(inode); 1735c6a9f7dSAndreas Gruenbacher 1745c6a9f7dSAndreas Gruenbacher dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, 1755c6a9f7dSAndreas Gruenbacher inode->i_ino, acl, dfacl); 1765c6a9f7dSAndreas Gruenbacher spin_lock(&inode->i_lock); 1775c6a9f7dSAndreas Gruenbacher __nfs3_forget_cached_acls(NFS_I(inode)); 1784814f56dSAndreas Gruenbacher if (!IS_ERR(acl)) 1795c6a9f7dSAndreas Gruenbacher nfsi->acl_access = posix_acl_dup(acl); 1804814f56dSAndreas Gruenbacher if (!IS_ERR(dfacl)) 1815c6a9f7dSAndreas Gruenbacher nfsi->acl_default = posix_acl_dup(dfacl); 1825c6a9f7dSAndreas Gruenbacher spin_unlock(&inode->i_lock); 1835c6a9f7dSAndreas Gruenbacher } 1845c6a9f7dSAndreas Gruenbacher 185b7fa0554SAndreas Gruenbacher struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) 186b7fa0554SAndreas Gruenbacher { 187b7fa0554SAndreas Gruenbacher struct nfs_server *server = NFS_SERVER(inode); 188b7fa0554SAndreas Gruenbacher struct nfs_fattr fattr; 189b7fa0554SAndreas Gruenbacher struct page *pages[NFSACL_MAXPAGES] = { }; 190b7fa0554SAndreas Gruenbacher struct nfs3_getaclargs args = { 191b7fa0554SAndreas Gruenbacher .fh = NFS_FH(inode), 192b7fa0554SAndreas Gruenbacher /* The xdr layer may allocate pages here. */ 193b7fa0554SAndreas Gruenbacher .pages = pages, 194b7fa0554SAndreas Gruenbacher }; 195b7fa0554SAndreas Gruenbacher struct nfs3_getaclres res = { 196b7fa0554SAndreas Gruenbacher .fattr = &fattr, 197b7fa0554SAndreas Gruenbacher }; 198dead28daSChuck Lever struct rpc_message msg = { 199dead28daSChuck Lever .rpc_argp = &args, 200dead28daSChuck Lever .rpc_resp = &res, 201dead28daSChuck Lever }; 2025c6a9f7dSAndreas Gruenbacher struct posix_acl *acl; 203b7fa0554SAndreas Gruenbacher int status, count; 204b7fa0554SAndreas Gruenbacher 205b7fa0554SAndreas Gruenbacher if (!nfs_server_capable(inode, NFS_CAP_ACLS)) 206b7fa0554SAndreas Gruenbacher return ERR_PTR(-EOPNOTSUPP); 207b7fa0554SAndreas Gruenbacher 2085c6a9f7dSAndreas Gruenbacher status = nfs_revalidate_inode(server, inode); 2095c6a9f7dSAndreas Gruenbacher if (status < 0) 2105c6a9f7dSAndreas Gruenbacher return ERR_PTR(status); 2115c6a9f7dSAndreas Gruenbacher acl = nfs3_get_cached_acl(inode, type); 2125c6a9f7dSAndreas Gruenbacher if (acl != ERR_PTR(-EAGAIN)) 2135c6a9f7dSAndreas Gruenbacher return acl; 2145c6a9f7dSAndreas Gruenbacher acl = NULL; 215b7fa0554SAndreas Gruenbacher 2165c6a9f7dSAndreas Gruenbacher /* 2175c6a9f7dSAndreas Gruenbacher * Only get the access acl when explicitly requested: We don't 2185c6a9f7dSAndreas Gruenbacher * need it for access decisions, and only some applications use 2195c6a9f7dSAndreas Gruenbacher * it. Applications which request the access acl first are not 2205c6a9f7dSAndreas Gruenbacher * penalized from this optimization. 2215c6a9f7dSAndreas Gruenbacher */ 2225c6a9f7dSAndreas Gruenbacher if (type == ACL_TYPE_ACCESS) 2235c6a9f7dSAndreas Gruenbacher args.mask |= NFS_ACLCNT|NFS_ACL; 2245c6a9f7dSAndreas Gruenbacher if (S_ISDIR(inode->i_mode)) 2255c6a9f7dSAndreas Gruenbacher args.mask |= NFS_DFACLCNT|NFS_DFACL; 2265c6a9f7dSAndreas Gruenbacher if (args.mask == 0) 227b7fa0554SAndreas Gruenbacher return NULL; 228b7fa0554SAndreas Gruenbacher 229b7fa0554SAndreas Gruenbacher dprintk("NFS call getacl\n"); 230dead28daSChuck Lever msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; 231f25b874dSJeff Layton nfs_fattr_init(&fattr); 232dead28daSChuck Lever status = rpc_call_sync(server->client_acl, &msg, 0); 233b7fa0554SAndreas Gruenbacher dprintk("NFS reply getacl: %d\n", status); 234b7fa0554SAndreas Gruenbacher 235b7fa0554SAndreas Gruenbacher /* pages may have been allocated at the xdr layer. */ 236b7fa0554SAndreas Gruenbacher for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) 237b7fa0554SAndreas Gruenbacher __free_page(args.pages[count]); 238b7fa0554SAndreas Gruenbacher 239b7fa0554SAndreas Gruenbacher switch (status) { 240b7fa0554SAndreas Gruenbacher case 0: 241b7fa0554SAndreas Gruenbacher status = nfs_refresh_inode(inode, &fattr); 242b7fa0554SAndreas Gruenbacher break; 243b7fa0554SAndreas Gruenbacher case -EPFNOSUPPORT: 244b7fa0554SAndreas Gruenbacher case -EPROTONOSUPPORT: 245b7fa0554SAndreas Gruenbacher dprintk("NFS_V3_ACL extension not supported; disabling\n"); 246b7fa0554SAndreas Gruenbacher server->caps &= ~NFS_CAP_ACLS; 247b7fa0554SAndreas Gruenbacher case -ENOTSUPP: 248b7fa0554SAndreas Gruenbacher status = -EOPNOTSUPP; 249b7fa0554SAndreas Gruenbacher default: 250b7fa0554SAndreas Gruenbacher goto getout; 251b7fa0554SAndreas Gruenbacher } 252b7fa0554SAndreas Gruenbacher if ((args.mask & res.mask) != args.mask) { 253b7fa0554SAndreas Gruenbacher status = -EIO; 254b7fa0554SAndreas Gruenbacher goto getout; 255b7fa0554SAndreas Gruenbacher } 256b7fa0554SAndreas Gruenbacher 257b7fa0554SAndreas Gruenbacher if (res.acl_access != NULL) { 258b7fa0554SAndreas Gruenbacher if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { 259b7fa0554SAndreas Gruenbacher posix_acl_release(res.acl_access); 260b7fa0554SAndreas Gruenbacher res.acl_access = NULL; 261b7fa0554SAndreas Gruenbacher } 262b7fa0554SAndreas Gruenbacher } 2634814f56dSAndreas Gruenbacher nfs3_cache_acls(inode, 2644814f56dSAndreas Gruenbacher (res.mask & NFS_ACL) ? res.acl_access : ERR_PTR(-EINVAL), 2654814f56dSAndreas Gruenbacher (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL)); 266b7fa0554SAndreas Gruenbacher 267b7fa0554SAndreas Gruenbacher switch(type) { 268b7fa0554SAndreas Gruenbacher case ACL_TYPE_ACCESS: 269b7fa0554SAndreas Gruenbacher acl = res.acl_access; 270b7fa0554SAndreas Gruenbacher res.acl_access = NULL; 271b7fa0554SAndreas Gruenbacher break; 272b7fa0554SAndreas Gruenbacher 273b7fa0554SAndreas Gruenbacher case ACL_TYPE_DEFAULT: 274b7fa0554SAndreas Gruenbacher acl = res.acl_default; 275b7fa0554SAndreas Gruenbacher res.acl_default = NULL; 276b7fa0554SAndreas Gruenbacher } 277b7fa0554SAndreas Gruenbacher 278b7fa0554SAndreas Gruenbacher getout: 279b7fa0554SAndreas Gruenbacher posix_acl_release(res.acl_access); 280b7fa0554SAndreas Gruenbacher posix_acl_release(res.acl_default); 281b7fa0554SAndreas Gruenbacher 282b7fa0554SAndreas Gruenbacher if (status != 0) { 283b7fa0554SAndreas Gruenbacher posix_acl_release(acl); 284b7fa0554SAndreas Gruenbacher acl = ERR_PTR(status); 285b7fa0554SAndreas Gruenbacher } 286b7fa0554SAndreas Gruenbacher return acl; 287b7fa0554SAndreas Gruenbacher } 288b7fa0554SAndreas Gruenbacher 289b7fa0554SAndreas Gruenbacher static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, 290b7fa0554SAndreas Gruenbacher struct posix_acl *dfacl) 291b7fa0554SAndreas Gruenbacher { 292b7fa0554SAndreas Gruenbacher struct nfs_server *server = NFS_SERVER(inode); 293b7fa0554SAndreas Gruenbacher struct nfs_fattr fattr; 294ae46141fSTrond Myklebust struct page *pages[NFSACL_MAXPAGES]; 295b7fa0554SAndreas Gruenbacher struct nfs3_setaclargs args = { 296b7fa0554SAndreas Gruenbacher .inode = inode, 297b7fa0554SAndreas Gruenbacher .mask = NFS_ACL, 298b7fa0554SAndreas Gruenbacher .acl_access = acl, 299b7fa0554SAndreas Gruenbacher .pages = pages, 300b7fa0554SAndreas Gruenbacher }; 301dead28daSChuck Lever struct rpc_message msg = { 302dead28daSChuck Lever .rpc_argp = &args, 303dead28daSChuck Lever .rpc_resp = &fattr, 304dead28daSChuck Lever }; 305ae46141fSTrond Myklebust int status; 306b7fa0554SAndreas Gruenbacher 307b7fa0554SAndreas Gruenbacher status = -EOPNOTSUPP; 308b7fa0554SAndreas Gruenbacher if (!nfs_server_capable(inode, NFS_CAP_ACLS)) 309b7fa0554SAndreas Gruenbacher goto out; 310b7fa0554SAndreas Gruenbacher 311b7fa0554SAndreas Gruenbacher /* We are doing this here, because XDR marshalling can only 312b7fa0554SAndreas Gruenbacher return -ENOMEM. */ 313b7fa0554SAndreas Gruenbacher status = -ENOSPC; 314b7fa0554SAndreas Gruenbacher if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) 315b7fa0554SAndreas Gruenbacher goto out; 316b7fa0554SAndreas Gruenbacher if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) 317b7fa0554SAndreas Gruenbacher goto out; 318b7fa0554SAndreas Gruenbacher if (S_ISDIR(inode->i_mode)) { 319b7fa0554SAndreas Gruenbacher args.mask |= NFS_DFACL; 320b7fa0554SAndreas Gruenbacher args.acl_default = dfacl; 321ae46141fSTrond Myklebust args.len = nfsacl_size(acl, dfacl); 322ae46141fSTrond Myklebust } else 323ae46141fSTrond Myklebust args.len = nfsacl_size(acl, NULL); 324ae46141fSTrond Myklebust 325ae46141fSTrond Myklebust if (args.len > NFS_ACL_INLINE_BUFSIZE) { 326ae46141fSTrond Myklebust unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT); 327ae46141fSTrond Myklebust 328ae46141fSTrond Myklebust status = -ENOMEM; 329ae46141fSTrond Myklebust do { 330ae46141fSTrond Myklebust args.pages[args.npages] = alloc_page(GFP_KERNEL); 331ae46141fSTrond Myklebust if (args.pages[args.npages] == NULL) 332ae46141fSTrond Myklebust goto out_freepages; 333ae46141fSTrond Myklebust args.npages++; 334ae46141fSTrond Myklebust } while (args.npages < npages); 335b7fa0554SAndreas Gruenbacher } 336b7fa0554SAndreas Gruenbacher 337b7fa0554SAndreas Gruenbacher dprintk("NFS call setacl\n"); 338dead28daSChuck Lever msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; 339f25b874dSJeff Layton nfs_fattr_init(&fattr); 340dead28daSChuck Lever status = rpc_call_sync(server->client_acl, &msg, 0); 341f41f7418STrond Myklebust nfs_access_zap_cache(inode); 342f41f7418STrond Myklebust nfs_zap_acl_cache(inode); 343b7fa0554SAndreas Gruenbacher dprintk("NFS reply setacl: %d\n", status); 344b7fa0554SAndreas Gruenbacher 345b7fa0554SAndreas Gruenbacher switch (status) { 346b7fa0554SAndreas Gruenbacher case 0: 347b7fa0554SAndreas Gruenbacher status = nfs_refresh_inode(inode, &fattr); 3484814f56dSAndreas Gruenbacher nfs3_cache_acls(inode, acl, dfacl); 349b7fa0554SAndreas Gruenbacher break; 350b7fa0554SAndreas Gruenbacher case -EPFNOSUPPORT: 351b7fa0554SAndreas Gruenbacher case -EPROTONOSUPPORT: 352b7fa0554SAndreas Gruenbacher dprintk("NFS_V3_ACL SETACL RPC not supported" 353b7fa0554SAndreas Gruenbacher "(will not retry)\n"); 354b7fa0554SAndreas Gruenbacher server->caps &= ~NFS_CAP_ACLS; 355b7fa0554SAndreas Gruenbacher case -ENOTSUPP: 356b7fa0554SAndreas Gruenbacher status = -EOPNOTSUPP; 357b7fa0554SAndreas Gruenbacher } 358ae46141fSTrond Myklebust out_freepages: 359ae46141fSTrond Myklebust while (args.npages != 0) { 360ae46141fSTrond Myklebust args.npages--; 361ae46141fSTrond Myklebust __free_page(args.pages[args.npages]); 362ae46141fSTrond Myklebust } 363b7fa0554SAndreas Gruenbacher out: 364b7fa0554SAndreas Gruenbacher return status; 365b7fa0554SAndreas Gruenbacher } 366b7fa0554SAndreas Gruenbacher 367b7fa0554SAndreas Gruenbacher int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) 368b7fa0554SAndreas Gruenbacher { 369b7fa0554SAndreas Gruenbacher struct posix_acl *alloc = NULL, *dfacl = NULL; 370b7fa0554SAndreas Gruenbacher int status; 371b7fa0554SAndreas Gruenbacher 372b7fa0554SAndreas Gruenbacher if (S_ISDIR(inode->i_mode)) { 373b7fa0554SAndreas Gruenbacher switch(type) { 374b7fa0554SAndreas Gruenbacher case ACL_TYPE_ACCESS: 375b7fa0554SAndreas Gruenbacher alloc = dfacl = nfs3_proc_getacl(inode, 376b7fa0554SAndreas Gruenbacher ACL_TYPE_DEFAULT); 377b7fa0554SAndreas Gruenbacher if (IS_ERR(alloc)) 378b7fa0554SAndreas Gruenbacher goto fail; 379b7fa0554SAndreas Gruenbacher break; 380b7fa0554SAndreas Gruenbacher 381b7fa0554SAndreas Gruenbacher case ACL_TYPE_DEFAULT: 382b7fa0554SAndreas Gruenbacher dfacl = acl; 383b7fa0554SAndreas Gruenbacher alloc = acl = nfs3_proc_getacl(inode, 384b7fa0554SAndreas Gruenbacher ACL_TYPE_ACCESS); 385b7fa0554SAndreas Gruenbacher if (IS_ERR(alloc)) 386b7fa0554SAndreas Gruenbacher goto fail; 387b7fa0554SAndreas Gruenbacher break; 388b7fa0554SAndreas Gruenbacher 389b7fa0554SAndreas Gruenbacher default: 390b7fa0554SAndreas Gruenbacher return -EINVAL; 391b7fa0554SAndreas Gruenbacher } 392b7fa0554SAndreas Gruenbacher } else if (type != ACL_TYPE_ACCESS) 393b7fa0554SAndreas Gruenbacher return -EINVAL; 394b7fa0554SAndreas Gruenbacher 395b7fa0554SAndreas Gruenbacher if (acl == NULL) { 396b7fa0554SAndreas Gruenbacher alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 397b7fa0554SAndreas Gruenbacher if (IS_ERR(alloc)) 398b7fa0554SAndreas Gruenbacher goto fail; 399b7fa0554SAndreas Gruenbacher } 400b7fa0554SAndreas Gruenbacher status = nfs3_proc_setacls(inode, acl, dfacl); 401b7fa0554SAndreas Gruenbacher posix_acl_release(alloc); 402b7fa0554SAndreas Gruenbacher return status; 403b7fa0554SAndreas Gruenbacher 404b7fa0554SAndreas Gruenbacher fail: 405b7fa0554SAndreas Gruenbacher return PTR_ERR(alloc); 406b7fa0554SAndreas Gruenbacher } 407055ffbeaSAndreas Gruenbacher 408055ffbeaSAndreas Gruenbacher int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, 409055ffbeaSAndreas Gruenbacher mode_t mode) 410055ffbeaSAndreas Gruenbacher { 411055ffbeaSAndreas Gruenbacher struct posix_acl *dfacl, *acl; 412055ffbeaSAndreas Gruenbacher int error = 0; 413055ffbeaSAndreas Gruenbacher 414055ffbeaSAndreas Gruenbacher dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); 415055ffbeaSAndreas Gruenbacher if (IS_ERR(dfacl)) { 416055ffbeaSAndreas Gruenbacher error = PTR_ERR(dfacl); 417055ffbeaSAndreas Gruenbacher return (error == -EOPNOTSUPP) ? 0 : error; 418055ffbeaSAndreas Gruenbacher } 419055ffbeaSAndreas Gruenbacher if (!dfacl) 420055ffbeaSAndreas Gruenbacher return 0; 421055ffbeaSAndreas Gruenbacher acl = posix_acl_clone(dfacl, GFP_KERNEL); 422055ffbeaSAndreas Gruenbacher error = -ENOMEM; 423055ffbeaSAndreas Gruenbacher if (!acl) 424055ffbeaSAndreas Gruenbacher goto out_release_dfacl; 425055ffbeaSAndreas Gruenbacher error = posix_acl_create_masq(acl, &mode); 426055ffbeaSAndreas Gruenbacher if (error < 0) 427055ffbeaSAndreas Gruenbacher goto out_release_acl; 428055ffbeaSAndreas Gruenbacher error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? 429055ffbeaSAndreas Gruenbacher dfacl : NULL); 430055ffbeaSAndreas Gruenbacher out_release_acl: 431055ffbeaSAndreas Gruenbacher posix_acl_release(acl); 432055ffbeaSAndreas Gruenbacher out_release_dfacl: 433055ffbeaSAndreas Gruenbacher posix_acl_release(dfacl); 434055ffbeaSAndreas Gruenbacher return error; 435055ffbeaSAndreas Gruenbacher } 436