root/fs/nfs/nfs3acl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs3_prepare_get_acl
  2. nfs3_complete_get_acl
  3. nfs3_abort_get_acl
  4. nfs3_get_acl
  5. __nfs3_proc_setacls
  6. nfs3_proc_setacls
  7. nfs3_set_acl
  8. nfs3_list_one_acl
  9. nfs3_listxattr

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/fs.h>
   3 #include <linux/gfp.h>
   4 #include <linux/nfs.h>
   5 #include <linux/nfs3.h>
   6 #include <linux/nfs_fs.h>
   7 #include <linux/posix_acl_xattr.h>
   8 #include <linux/nfsacl.h>
   9 
  10 #include "internal.h"
  11 #include "nfs3_fs.h"
  12 
  13 #define NFSDBG_FACILITY NFSDBG_PROC
  14 
  15 /*
  16  * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for
  17  * caching get_acl results in a race-free way.  See fs/posix_acl.c:get_acl()
  18  * for explanations.
  19  */
  20 static void nfs3_prepare_get_acl(struct posix_acl **p)
  21 {
  22         struct posix_acl *sentinel = uncached_acl_sentinel(current);
  23 
  24         if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) {
  25                 /* Not the first reader or sentinel already in place. */
  26         }
  27 }
  28 
  29 static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl)
  30 {
  31         struct posix_acl *sentinel = uncached_acl_sentinel(current);
  32 
  33         /* Only cache the ACL if our sentinel is still in place. */
  34         posix_acl_dup(acl);
  35         if (cmpxchg(p, sentinel, acl) != sentinel)
  36                 posix_acl_release(acl);
  37 }
  38 
  39 static void nfs3_abort_get_acl(struct posix_acl **p)
  40 {
  41         struct posix_acl *sentinel = uncached_acl_sentinel(current);
  42 
  43         /* Remove our sentinel upon failure. */
  44         cmpxchg(p, sentinel, ACL_NOT_CACHED);
  45 }
  46 
  47 struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
  48 {
  49         struct nfs_server *server = NFS_SERVER(inode);
  50         struct page *pages[NFSACL_MAXPAGES] = { };
  51         struct nfs3_getaclargs args = {
  52                 .fh = NFS_FH(inode),
  53                 /* The xdr layer may allocate pages here. */
  54                 .pages = pages,
  55         };
  56         struct nfs3_getaclres res = {
  57                 NULL,
  58         };
  59         struct rpc_message msg = {
  60                 .rpc_argp       = &args,
  61                 .rpc_resp       = &res,
  62         };
  63         int status, count;
  64 
  65         if (!nfs_server_capable(inode, NFS_CAP_ACLS))
  66                 return ERR_PTR(-EOPNOTSUPP);
  67 
  68         status = nfs_revalidate_inode(server, inode);
  69         if (status < 0)
  70                 return ERR_PTR(status);
  71 
  72         /*
  73          * Only get the access acl when explicitly requested: We don't
  74          * need it for access decisions, and only some applications use
  75          * it. Applications which request the access acl first are not
  76          * penalized from this optimization.
  77          */
  78         if (type == ACL_TYPE_ACCESS)
  79                 args.mask |= NFS_ACLCNT|NFS_ACL;
  80         if (S_ISDIR(inode->i_mode))
  81                 args.mask |= NFS_DFACLCNT|NFS_DFACL;
  82         if (args.mask == 0)
  83                 return NULL;
  84 
  85         dprintk("NFS call getacl\n");
  86         msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
  87         res.fattr = nfs_alloc_fattr();
  88         if (res.fattr == NULL)
  89                 return ERR_PTR(-ENOMEM);
  90 
  91         if (args.mask & NFS_ACL)
  92                 nfs3_prepare_get_acl(&inode->i_acl);
  93         if (args.mask & NFS_DFACL)
  94                 nfs3_prepare_get_acl(&inode->i_default_acl);
  95 
  96         status = rpc_call_sync(server->client_acl, &msg, 0);
  97         dprintk("NFS reply getacl: %d\n", status);
  98 
  99         /* pages may have been allocated at the xdr layer. */
 100         for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
 101                 __free_page(args.pages[count]);
 102 
 103         switch (status) {
 104                 case 0:
 105                         status = nfs_refresh_inode(inode, res.fattr);
 106                         break;
 107                 case -EPFNOSUPPORT:
 108                 case -EPROTONOSUPPORT:
 109                         dprintk("NFS_V3_ACL extension not supported; disabling\n");
 110                         server->caps &= ~NFS_CAP_ACLS;
 111                         /* fall through */
 112                 case -ENOTSUPP:
 113                         status = -EOPNOTSUPP;
 114                 default:
 115                         goto getout;
 116         }
 117         if ((args.mask & res.mask) != args.mask) {
 118                 status = -EIO;
 119                 goto getout;
 120         }
 121 
 122         if (res.acl_access != NULL) {
 123                 if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) ||
 124                     res.acl_access->a_count == 0) {
 125                         posix_acl_release(res.acl_access);
 126                         res.acl_access = NULL;
 127                 }
 128         }
 129 
 130         if (res.mask & NFS_ACL)
 131                 nfs3_complete_get_acl(&inode->i_acl, res.acl_access);
 132         else
 133                 forget_cached_acl(inode, ACL_TYPE_ACCESS);
 134 
 135         if (res.mask & NFS_DFACL)
 136                 nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default);
 137         else
 138                 forget_cached_acl(inode, ACL_TYPE_DEFAULT);
 139 
 140         nfs_free_fattr(res.fattr);
 141         if (type == ACL_TYPE_ACCESS) {
 142                 posix_acl_release(res.acl_default);
 143                 return res.acl_access;
 144         } else {
 145                 posix_acl_release(res.acl_access);
 146                 return res.acl_default;
 147         }
 148 
 149 getout:
 150         nfs3_abort_get_acl(&inode->i_acl);
 151         nfs3_abort_get_acl(&inode->i_default_acl);
 152         posix_acl_release(res.acl_access);
 153         posix_acl_release(res.acl_default);
 154         nfs_free_fattr(res.fattr);
 155         return ERR_PTR(status);
 156 }
 157 
 158 static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
 159                 struct posix_acl *dfacl)
 160 {
 161         struct nfs_server *server = NFS_SERVER(inode);
 162         struct nfs_fattr *fattr;
 163         struct page *pages[NFSACL_MAXPAGES];
 164         struct nfs3_setaclargs args = {
 165                 .inode = inode,
 166                 .mask = NFS_ACL,
 167                 .acl_access = acl,
 168                 .pages = pages,
 169         };
 170         struct rpc_message msg = {
 171                 .rpc_argp       = &args,
 172                 .rpc_resp       = &fattr,
 173         };
 174         int status = 0;
 175 
 176         if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL))
 177                 goto out;
 178 
 179         status = -EOPNOTSUPP;
 180         if (!nfs_server_capable(inode, NFS_CAP_ACLS))
 181                 goto out;
 182 
 183         /* We are doing this here because XDR marshalling does not
 184          * return any results, it BUGs. */
 185         status = -ENOSPC;
 186         if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
 187                 goto out;
 188         if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
 189                 goto out;
 190         if (S_ISDIR(inode->i_mode)) {
 191                 args.mask |= NFS_DFACL;
 192                 args.acl_default = dfacl;
 193                 args.len = nfsacl_size(acl, dfacl);
 194         } else
 195                 args.len = nfsacl_size(acl, NULL);
 196 
 197         if (args.len > NFS_ACL_INLINE_BUFSIZE) {
 198                 unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
 199 
 200                 status = -ENOMEM;
 201                 do {
 202                         args.pages[args.npages] = alloc_page(GFP_KERNEL);
 203                         if (args.pages[args.npages] == NULL)
 204                                 goto out_freepages;
 205                         args.npages++;
 206                 } while (args.npages < npages);
 207         }
 208 
 209         dprintk("NFS call setacl\n");
 210         status = -ENOMEM;
 211         fattr = nfs_alloc_fattr();
 212         if (fattr == NULL)
 213                 goto out_freepages;
 214 
 215         msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
 216         msg.rpc_resp = fattr;
 217         status = rpc_call_sync(server->client_acl, &msg, 0);
 218         nfs_access_zap_cache(inode);
 219         nfs_zap_acl_cache(inode);
 220         dprintk("NFS reply setacl: %d\n", status);
 221 
 222         switch (status) {
 223                 case 0:
 224                         status = nfs_refresh_inode(inode, fattr);
 225                         break;
 226                 case -EPFNOSUPPORT:
 227                 case -EPROTONOSUPPORT:
 228                         dprintk("NFS_V3_ACL SETACL RPC not supported"
 229                                         "(will not retry)\n");
 230                         server->caps &= ~NFS_CAP_ACLS;
 231                         /* fall through */
 232                 case -ENOTSUPP:
 233                         status = -EOPNOTSUPP;
 234         }
 235         nfs_free_fattr(fattr);
 236 out_freepages:
 237         while (args.npages != 0) {
 238                 args.npages--;
 239                 __free_page(args.pages[args.npages]);
 240         }
 241 out:
 242         return status;
 243 }
 244 
 245 int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
 246                 struct posix_acl *dfacl)
 247 {
 248         int ret;
 249         ret = __nfs3_proc_setacls(inode, acl, dfacl);
 250         return (ret == -EOPNOTSUPP) ? 0 : ret;
 251 
 252 }
 253 
 254 int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 255 {
 256         struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
 257         int status;
 258 
 259         if (S_ISDIR(inode->i_mode)) {
 260                 switch(type) {
 261                 case ACL_TYPE_ACCESS:
 262                         alloc = get_acl(inode, ACL_TYPE_DEFAULT);
 263                         if (IS_ERR(alloc))
 264                                 goto fail;
 265                         dfacl = alloc;
 266                         break;
 267 
 268                 case ACL_TYPE_DEFAULT:
 269                         alloc = get_acl(inode, ACL_TYPE_ACCESS);
 270                         if (IS_ERR(alloc))
 271                                 goto fail;
 272                         dfacl = acl;
 273                         acl = alloc;
 274                         break;
 275                 }
 276         }
 277 
 278         if (acl == NULL) {
 279                 alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
 280                 if (IS_ERR(alloc))
 281                         goto fail;
 282                 acl = alloc;
 283         }
 284         status = __nfs3_proc_setacls(inode, acl, dfacl);
 285 out:
 286         if (acl != orig)
 287                 posix_acl_release(acl);
 288         if (dfacl != orig)
 289                 posix_acl_release(dfacl);
 290         return status;
 291 
 292 fail:
 293         status = PTR_ERR(alloc);
 294         goto out;
 295 }
 296 
 297 const struct xattr_handler *nfs3_xattr_handlers[] = {
 298         &posix_acl_access_xattr_handler,
 299         &posix_acl_default_xattr_handler,
 300         NULL,
 301 };
 302 
 303 static int
 304 nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data,
 305                 size_t size, ssize_t *result)
 306 {
 307         struct posix_acl *acl;
 308         char *p = data + *result;
 309 
 310         acl = get_acl(inode, type);
 311         if (IS_ERR_OR_NULL(acl))
 312                 return 0;
 313 
 314         posix_acl_release(acl);
 315 
 316         *result += strlen(name);
 317         *result += 1;
 318         if (!size)
 319                 return 0;
 320         if (*result > size)
 321                 return -ERANGE;
 322 
 323         strcpy(p, name);
 324         return 0;
 325 }
 326 
 327 ssize_t
 328 nfs3_listxattr(struct dentry *dentry, char *data, size_t size)
 329 {
 330         struct inode *inode = d_inode(dentry);
 331         ssize_t result = 0;
 332         int error;
 333 
 334         error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS,
 335                         XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result);
 336         if (error)
 337                 return error;
 338 
 339         error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT,
 340                         XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result);
 341         if (error)
 342                 return error;
 343         return result;
 344 }

/* [<][>][^][v][top][bottom][index][help] */