LCOV - code coverage report
Current view: top level - fs/nfs - nfs3acl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 167 0.0 %
Date: 2014-02-18 Functions: 0 12 0.0 %
Branches: 0 139 0.0 %

           Branch data     Line data    Source code
       1                 :            : #include <linux/fs.h>
       2                 :            : #include <linux/gfp.h>
       3                 :            : #include <linux/nfs.h>
       4                 :            : #include <linux/nfs3.h>
       5                 :            : #include <linux/nfs_fs.h>
       6                 :            : #include <linux/posix_acl_xattr.h>
       7                 :            : #include <linux/nfsacl.h>
       8                 :            : 
       9                 :            : #include "internal.h"
      10                 :            : 
      11                 :            : #define NFSDBG_FACILITY NFSDBG_PROC
      12                 :            : 
      13                 :          0 : ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
      14                 :            : {
      15                 :          0 :         struct inode *inode = dentry->d_inode;
      16                 :            :         struct posix_acl *acl;
      17                 :            :         int pos=0, len=0;
      18                 :            : 
      19                 :            : #       define output(s) do {                                           \
      20                 :            :                         if (pos + sizeof(s) <= size) {                       \
      21                 :            :                                 memcpy(buffer + pos, s, sizeof(s));     \
      22                 :            :                                 pos += sizeof(s);                       \
      23                 :            :                         }                                               \
      24                 :            :                         len += sizeof(s);                               \
      25                 :            :                 } while(0)
      26                 :            : 
      27                 :          0 :         acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS);
      28         [ #  # ]:          0 :         if (IS_ERR(acl))
      29                 :            :                 return PTR_ERR(acl);
      30         [ #  # ]:          0 :         if (acl) {
      31         [ #  # ]:          0 :                 output("system.posix_acl_access");
      32                 :            :                 posix_acl_release(acl);
      33                 :            :         }
      34                 :            : 
      35         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode)) {
      36                 :          0 :                 acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT);
      37         [ #  # ]:          0 :                 if (IS_ERR(acl))
      38                 :          0 :                         return PTR_ERR(acl);
      39         [ #  # ]:          0 :                 if (acl) {
      40         [ #  # ]:          0 :                         output("system.posix_acl_default");
      41                 :            :                         posix_acl_release(acl);
      42                 :            :                 }
      43                 :            :         }
      44                 :            : 
      45                 :            : #       undef output
      46                 :            : 
      47         [ #  # ]:          0 :         if (!buffer || len <= size)
      48                 :          0 :                 return len;
      49                 :            :         return -ERANGE;
      50                 :            : }
      51                 :            : 
      52                 :          0 : ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
      53                 :            :                 void *buffer, size_t size)
      54                 :            : {
      55                 :          0 :         struct inode *inode = dentry->d_inode;
      56                 :            :         struct posix_acl *acl;
      57                 :            :         int type, error = 0;
      58                 :            : 
      59         [ #  # ]:          0 :         if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
      60                 :            :                 type = ACL_TYPE_ACCESS;
      61         [ #  # ]:          0 :         else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
      62                 :            :                 type = ACL_TYPE_DEFAULT;
      63                 :            :         else
      64                 :            :                 return -EOPNOTSUPP;
      65                 :            : 
      66                 :          0 :         acl = nfs3_proc_getacl(inode, type);
      67         [ #  # ]:          0 :         if (IS_ERR(acl))
      68                 :          0 :                 return PTR_ERR(acl);
      69         [ #  # ]:          0 :         else if (acl) {
      70 [ #  # ][ #  # ]:          0 :                 if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
      71                 :            :                         error = -ENODATA;
      72                 :            :                 else
      73                 :          0 :                         error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
      74                 :            :                 posix_acl_release(acl);
      75                 :            :         } else
      76                 :            :                 error = -ENODATA;
      77                 :            : 
      78                 :          0 :         return error;
      79                 :            : }
      80                 :            : 
      81                 :          0 : int nfs3_setxattr(struct dentry *dentry, const char *name,
      82                 :            :              const void *value, size_t size, int flags)
      83                 :            : {
      84                 :          0 :         struct inode *inode = dentry->d_inode;
      85                 :            :         struct posix_acl *acl;
      86                 :            :         int type, error;
      87                 :            : 
      88         [ #  # ]:          0 :         if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
      89                 :            :                 type = ACL_TYPE_ACCESS;
      90         [ #  # ]:          0 :         else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
      91                 :            :                 type = ACL_TYPE_DEFAULT;
      92                 :            :         else
      93                 :            :                 return -EOPNOTSUPP;
      94                 :            : 
      95                 :          0 :         acl = posix_acl_from_xattr(&init_user_ns, value, size);
      96         [ #  # ]:          0 :         if (IS_ERR(acl))
      97                 :          0 :                 return PTR_ERR(acl);
      98                 :          0 :         error = nfs3_proc_setacl(inode, type, acl);
      99                 :            :         posix_acl_release(acl);
     100                 :            : 
     101                 :          0 :         return error;
     102                 :            : }
     103                 :            : 
     104                 :          0 : int nfs3_removexattr(struct dentry *dentry, const char *name)
     105                 :            : {
     106                 :          0 :         struct inode *inode = dentry->d_inode;
     107                 :            :         int type;
     108                 :            : 
     109         [ #  # ]:          0 :         if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
     110                 :            :                 type = ACL_TYPE_ACCESS;
     111         [ #  # ]:          0 :         else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
     112                 :            :                 type = ACL_TYPE_DEFAULT;
     113                 :            :         else
     114                 :            :                 return -EOPNOTSUPP;
     115                 :            : 
     116                 :          0 :         return nfs3_proc_setacl(inode, type, NULL);
     117                 :            : }
     118                 :            : 
     119                 :          0 : static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
     120                 :            : {
     121         [ #  # ]:          0 :         if (!IS_ERR(nfsi->acl_access)) {
     122                 :            :                 posix_acl_release(nfsi->acl_access);
     123                 :          0 :                 nfsi->acl_access = ERR_PTR(-EAGAIN);
     124                 :            :         }
     125         [ #  # ]:          0 :         if (!IS_ERR(nfsi->acl_default)) {
     126                 :            :                 posix_acl_release(nfsi->acl_default);
     127                 :          0 :                 nfsi->acl_default = ERR_PTR(-EAGAIN);
     128                 :            :         }
     129                 :          0 : }
     130                 :            : 
     131                 :          0 : void nfs3_forget_cached_acls(struct inode *inode)
     132                 :            : {
     133                 :            :         dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id,
     134                 :            :                 inode->i_ino);
     135                 :            :         spin_lock(&inode->i_lock);
     136                 :          0 :         __nfs3_forget_cached_acls(NFS_I(inode));
     137                 :            :         spin_unlock(&inode->i_lock);
     138                 :          0 : }
     139                 :            : 
     140                 :          0 : static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type)
     141                 :            : {
     142                 :            :         struct nfs_inode *nfsi = NFS_I(inode);
     143                 :            :         struct posix_acl *acl = ERR_PTR(-EINVAL);
     144                 :            : 
     145                 :            :         spin_lock(&inode->i_lock);
     146      [ #  #  # ]:          0 :         switch(type) {
     147                 :            :                 case ACL_TYPE_ACCESS:
     148                 :          0 :                         acl = nfsi->acl_access;
     149                 :          0 :                         break;
     150                 :            : 
     151                 :            :                 case ACL_TYPE_DEFAULT:
     152                 :          0 :                         acl = nfsi->acl_default;
     153                 :          0 :                         break;
     154                 :            : 
     155                 :            :                 default:
     156                 :            :                         goto out;
     157                 :            :         }
     158         [ #  # ]:          0 :         if (IS_ERR(acl))
     159                 :            :                 acl = ERR_PTR(-EAGAIN);
     160                 :            :         else
     161                 :            :                 acl = posix_acl_dup(acl);
     162                 :            : out:
     163                 :            :         spin_unlock(&inode->i_lock);
     164                 :            :         dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id,
     165                 :            :                 inode->i_ino, type, acl);
     166                 :          0 :         return acl;
     167                 :            : }
     168                 :            : 
     169                 :          0 : static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl,
     170                 :            :                     struct posix_acl *dfacl)
     171                 :            : {
     172                 :            :         struct nfs_inode *nfsi = NFS_I(inode);
     173                 :            : 
     174                 :            :         dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id,
     175                 :            :                 inode->i_ino, acl, dfacl);
     176                 :            :         spin_lock(&inode->i_lock);
     177                 :          0 :         __nfs3_forget_cached_acls(NFS_I(inode));
     178         [ #  # ]:          0 :         if (!IS_ERR(acl))
     179                 :          0 :                 nfsi->acl_access = posix_acl_dup(acl);
     180         [ #  # ]:          0 :         if (!IS_ERR(dfacl))
     181                 :          0 :                 nfsi->acl_default = posix_acl_dup(dfacl);
     182                 :            :         spin_unlock(&inode->i_lock);
     183                 :          0 : }
     184                 :            : 
     185                 :          0 : struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
     186                 :            : {
     187                 :            :         struct nfs_server *server = NFS_SERVER(inode);
     188                 :          0 :         struct page *pages[NFSACL_MAXPAGES] = { };
     189                 :          0 :         struct nfs3_getaclargs args = {
     190                 :          0 :                 .fh = NFS_FH(inode),
     191                 :            :                 /* The xdr layer may allocate pages here. */
     192                 :            :                 .pages = pages,
     193                 :            :         };
     194                 :          0 :         struct nfs3_getaclres res = {
     195                 :            :                 NULL,
     196                 :            :         };
     197                 :          0 :         struct rpc_message msg = {
     198                 :            :                 .rpc_argp       = &args,
     199                 :            :                 .rpc_resp       = &res,
     200                 :            :         };
     201                 :            :         struct posix_acl *acl;
     202                 :            :         int status, count;
     203                 :            : 
     204         [ #  # ]:          0 :         if (!nfs_server_capable(inode, NFS_CAP_ACLS))
     205                 :            :                 return ERR_PTR(-EOPNOTSUPP);
     206                 :            : 
     207                 :          0 :         status = nfs_revalidate_inode(server, inode);
     208         [ #  # ]:          0 :         if (status < 0)
     209                 :          0 :                 return ERR_PTR(status);
     210                 :          0 :         acl = nfs3_get_cached_acl(inode, type);
     211         [ #  # ]:          0 :         if (acl != ERR_PTR(-EAGAIN))
     212                 :            :                 return acl;
     213                 :            :         acl = NULL;
     214                 :            : 
     215                 :            :         /*
     216                 :            :          * Only get the access acl when explicitly requested: We don't
     217                 :            :          * need it for access decisions, and only some applications use
     218                 :            :          * it. Applications which request the access acl first are not
     219                 :            :          * penalized from this optimization.
     220                 :            :          */
     221         [ #  # ]:          0 :         if (type == ACL_TYPE_ACCESS)
     222                 :          0 :                 args.mask |= NFS_ACLCNT|NFS_ACL;
     223         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode))
     224                 :          0 :                 args.mask |= NFS_DFACLCNT|NFS_DFACL;
     225         [ #  # ]:          0 :         if (args.mask == 0)
     226                 :            :                 return NULL;
     227                 :            : 
     228                 :            :         dprintk("NFS call getacl\n");
     229                 :          0 :         msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
     230                 :          0 :         res.fattr = nfs_alloc_fattr();
     231         [ #  # ]:          0 :         if (res.fattr == NULL)
     232                 :            :                 return ERR_PTR(-ENOMEM);
     233                 :            : 
     234                 :          0 :         status = rpc_call_sync(server->client_acl, &msg, 0);
     235                 :            :         dprintk("NFS reply getacl: %d\n", status);
     236                 :            : 
     237                 :            :         /* pages may have been allocated at the xdr layer. */
     238 [ #  # ][ #  # ]:          0 :         for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
     239                 :          0 :                 __free_page(args.pages[count]);
     240                 :            : 
     241   [ #  #  #  # ]:          0 :         switch (status) {
     242                 :            :                 case 0:
     243                 :          0 :                         status = nfs_refresh_inode(inode, res.fattr);
     244                 :            :                         break;
     245                 :            :                 case -EPFNOSUPPORT:
     246                 :            :                 case -EPROTONOSUPPORT:
     247                 :            :                         dprintk("NFS_V3_ACL extension not supported; disabling\n");
     248                 :          0 :                         server->caps &= ~NFS_CAP_ACLS;
     249                 :            :                 case -ENOTSUPP:
     250                 :            :                         status = -EOPNOTSUPP;
     251                 :            :                 default:
     252                 :            :                         goto getout;
     253                 :            :         }
     254         [ #  # ]:          0 :         if ((args.mask & res.mask) != args.mask) {
     255                 :            :                 status = -EIO;
     256                 :            :                 goto getout;
     257                 :            :         }
     258                 :            : 
     259         [ #  # ]:          0 :         if (res.acl_access != NULL) {
     260         [ #  # ]:          0 :                 if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) {
     261                 :          0 :                         posix_acl_release(res.acl_access);
     262                 :          0 :                         res.acl_access = NULL;
     263                 :            :                 }
     264                 :            :         }
     265 [ #  # ][ #  # ]:          0 :         nfs3_cache_acls(inode,
     266                 :          0 :                 (res.mask & NFS_ACL)   ? res.acl_access  : ERR_PTR(-EINVAL),
     267                 :          0 :                 (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL));
     268                 :            : 
     269      [ #  #  # ]:          0 :         switch(type) {
     270                 :            :                 case ACL_TYPE_ACCESS:
     271                 :          0 :                         acl = res.acl_access;
     272                 :          0 :                         res.acl_access = NULL;
     273                 :          0 :                         break;
     274                 :            : 
     275                 :            :                 case ACL_TYPE_DEFAULT:
     276                 :          0 :                         acl = res.acl_default;
     277                 :          0 :                         res.acl_default = NULL;
     278                 :            :         }
     279                 :            : 
     280                 :            : getout:
     281                 :          0 :         posix_acl_release(res.acl_access);
     282                 :          0 :         posix_acl_release(res.acl_default);
     283                 :          0 :         nfs_free_fattr(res.fattr);
     284                 :            : 
     285         [ #  # ]:          0 :         if (status != 0) {
     286                 :            :                 posix_acl_release(acl);
     287                 :            :                 acl = ERR_PTR(status);
     288                 :            :         }
     289                 :          0 :         return acl;
     290                 :            : }
     291                 :            : 
     292                 :          0 : static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
     293                 :            :                   struct posix_acl *dfacl)
     294                 :            : {
     295                 :            :         struct nfs_server *server = NFS_SERVER(inode);
     296                 :            :         struct nfs_fattr *fattr;
     297                 :            :         struct page *pages[NFSACL_MAXPAGES];
     298                 :          0 :         struct nfs3_setaclargs args = {
     299                 :            :                 .inode = inode,
     300                 :            :                 .mask = NFS_ACL,
     301                 :            :                 .acl_access = acl,
     302                 :            :                 .pages = pages,
     303                 :            :         };
     304                 :          0 :         struct rpc_message msg = {
     305                 :            :                 .rpc_argp       = &args,
     306                 :            :                 .rpc_resp       = &fattr,
     307                 :            :         };
     308                 :            :         int status;
     309                 :            : 
     310                 :            :         status = -EOPNOTSUPP;
     311         [ #  # ]:          0 :         if (!nfs_server_capable(inode, NFS_CAP_ACLS))
     312                 :            :                 goto out;
     313                 :            : 
     314                 :            :         /* We are doing this here because XDR marshalling does not
     315                 :            :          * return any results, it BUGs. */
     316                 :            :         status = -ENOSPC;
     317 [ #  # ][ #  # ]:          0 :         if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
     318                 :            :                 goto out;
     319 [ #  # ][ #  # ]:          0 :         if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
     320                 :            :                 goto out;
     321         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode)) {
     322                 :          0 :                 args.mask |= NFS_DFACL;
     323                 :          0 :                 args.acl_default = dfacl;
     324                 :          0 :                 args.len = nfsacl_size(acl, dfacl);
     325                 :            :         } else
     326                 :          0 :                 args.len = nfsacl_size(acl, NULL);
     327                 :            : 
     328         [ #  # ]:          0 :         if (args.len > NFS_ACL_INLINE_BUFSIZE) {
     329                 :          0 :                 unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
     330                 :            : 
     331                 :            :                 status = -ENOMEM;
     332                 :            :                 do {
     333                 :          0 :                         args.pages[args.npages] = alloc_page(GFP_KERNEL);
     334         [ #  # ]:          0 :                         if (args.pages[args.npages] == NULL)
     335                 :            :                                 goto out_freepages;
     336                 :          0 :                         args.npages++;
     337         [ #  # ]:          0 :                 } while (args.npages < npages);
     338                 :            :         }
     339                 :            : 
     340                 :            :         dprintk("NFS call setacl\n");
     341                 :            :         status = -ENOMEM;
     342                 :          0 :         fattr = nfs_alloc_fattr();
     343         [ #  # ]:          0 :         if (fattr == NULL)
     344                 :            :                 goto out_freepages;
     345                 :            : 
     346                 :          0 :         msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
     347                 :          0 :         msg.rpc_resp = fattr;
     348                 :          0 :         status = rpc_call_sync(server->client_acl, &msg, 0);
     349                 :          0 :         nfs_access_zap_cache(inode);
     350                 :          0 :         nfs_zap_acl_cache(inode);
     351                 :            :         dprintk("NFS reply setacl: %d\n", status);
     352                 :            : 
     353   [ #  #  #  # ]:          0 :         switch (status) {
     354                 :            :                 case 0:
     355                 :          0 :                         status = nfs_refresh_inode(inode, fattr);
     356                 :          0 :                         nfs3_cache_acls(inode, acl, dfacl);
     357                 :          0 :                         break;
     358                 :            :                 case -EPFNOSUPPORT:
     359                 :            :                 case -EPROTONOSUPPORT:
     360                 :            :                         dprintk("NFS_V3_ACL SETACL RPC not supported"
     361                 :            :                                         "(will not retry)\n");
     362                 :          0 :                         server->caps &= ~NFS_CAP_ACLS;
     363                 :            :                 case -ENOTSUPP:
     364                 :            :                         status = -EOPNOTSUPP;
     365                 :            :         }
     366                 :          0 :         nfs_free_fattr(fattr);
     367                 :            : out_freepages:
     368         [ #  # ]:          0 :         while (args.npages != 0) {
     369                 :          0 :                 args.npages--;
     370                 :          0 :                 __free_page(args.pages[args.npages]);
     371                 :            :         }
     372                 :            : out:
     373                 :          0 :         return status;
     374                 :            : }
     375                 :            : 
     376                 :          0 : int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
     377                 :            : {
     378                 :            :         struct posix_acl *alloc = NULL, *dfacl = NULL;
     379                 :            :         int status;
     380                 :            : 
     381         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode)) {
     382      [ #  #  # ]:          0 :                 switch(type) {
     383                 :            :                         case ACL_TYPE_ACCESS:
     384                 :          0 :                                 alloc = dfacl = nfs3_proc_getacl(inode,
     385                 :            :                                                 ACL_TYPE_DEFAULT);
     386         [ #  # ]:          0 :                                 if (IS_ERR(alloc))
     387                 :            :                                         goto fail;
     388                 :            :                                 break;
     389                 :            : 
     390                 :            :                         case ACL_TYPE_DEFAULT:
     391                 :            :                                 dfacl = acl;
     392                 :          0 :                                 alloc = acl = nfs3_proc_getacl(inode,
     393                 :            :                                                 ACL_TYPE_ACCESS);
     394         [ #  # ]:          0 :                                 if (IS_ERR(alloc))
     395                 :            :                                         goto fail;
     396                 :            :                                 break;
     397                 :            : 
     398                 :            :                         default:
     399                 :            :                                 return -EINVAL;
     400                 :            :                 }
     401         [ #  # ]:          0 :         } else if (type != ACL_TYPE_ACCESS)
     402                 :            :                         return -EINVAL;
     403                 :            : 
     404         [ #  # ]:          0 :         if (acl == NULL) {
     405                 :          0 :                 alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
     406         [ #  # ]:          0 :                 if (IS_ERR(alloc))
     407                 :            :                         goto fail;
     408                 :            :         }
     409                 :          0 :         status = nfs3_proc_setacls(inode, acl, dfacl);
     410                 :            :         posix_acl_release(alloc);
     411                 :          0 :         return status;
     412                 :            : 
     413                 :            : fail:
     414                 :          0 :         return PTR_ERR(alloc);
     415                 :            : }
     416                 :            : 
     417                 :          0 : int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
     418                 :            :                 umode_t mode)
     419                 :            : {
     420                 :            :         struct posix_acl *dfacl, *acl;
     421                 :            :         int error = 0;
     422                 :            : 
     423                 :          0 :         dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT);
     424         [ #  # ]:          0 :         if (IS_ERR(dfacl)) {
     425                 :            :                 error = PTR_ERR(dfacl);
     426         [ #  # ]:          0 :                 return (error == -EOPNOTSUPP) ? 0 : error;
     427                 :            :         }
     428         [ #  # ]:          0 :         if (!dfacl)
     429                 :            :                 return 0;
     430                 :          0 :         acl = posix_acl_dup(dfacl);
     431                 :          0 :         error = posix_acl_create(&acl, GFP_KERNEL, &mode);
     432         [ #  # ]:          0 :         if (error < 0)
     433                 :            :                 goto out_release_dfacl;
     434         [ #  # ]:          0 :         error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ?
     435                 :            :                                                       dfacl : NULL);
     436                 :          0 :         posix_acl_release(acl);
     437                 :            : out_release_dfacl:
     438                 :            :         posix_acl_release(dfacl);
     439                 :          0 :         return error;
     440                 :            : }

Generated by: LCOV version 1.9