]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
NFS: change access cache to use 'struct cred'.
authorNeilBrown <neilb@suse.com>
Mon, 3 Dec 2018 00:30:30 +0000 (11:30 +1100)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 19 Dec 2018 18:52:45 +0000 (13:52 -0500)
Rather than keying the access cache with 'struct rpc_cred',
use 'struct cred'.  Then use cred_fscmp() to compare
credentials rather than comparing the raw pointer.

A benefit of this approach is that in the common case we avoid the
rpc_lookup_cred_nonblock() call which can be slow when the cred cache is large.
This also keeps many fewer items pinned in the rpc cred cache, so the
cred cache is less likely to get large.

Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/dir.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
include/linux/nfs_fs.h

index 71b2e390becf23fca2860250c2e85cb85ed7d733..4dc61b6f74e82dbac99719dde47a2d25e468c55d 100644 (file)
@@ -2139,7 +2139,7 @@ MODULE_PARM_DESC(nfs_access_max_cachesize, "NFS access maximum total cache lengt
 
 static void nfs_access_free_entry(struct nfs_access_entry *entry)
 {
-       put_rpccred(entry->cred);
+       put_cred(entry->cred);
        kfree_rcu(entry, rcu_head);
        smp_mb__before_atomic();
        atomic_long_dec(&nfs_access_nr_entries);
@@ -2265,17 +2265,18 @@ void nfs_access_zap_cache(struct inode *inode)
 }
 EXPORT_SYMBOL_GPL(nfs_access_zap_cache);
 
-static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred)
+static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
 {
        struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
-       struct nfs_access_entry *entry;
 
        while (n != NULL) {
-               entry = rb_entry(n, struct nfs_access_entry, rb_node);
+               struct nfs_access_entry *entry =
+                       rb_entry(n, struct nfs_access_entry, rb_node);
+               int cmp = cred_fscmp(cred, entry->cred);
 
-               if (cred < entry->cred)
+               if (cmp < 0)
                        n = n->rb_left;
-               else if (cred > entry->cred)
+               else if (cmp > 0)
                        n = n->rb_right;
                else
                        return entry;
@@ -2283,7 +2284,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
        return NULL;
 }
 
-static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res, bool may_block)
+static int nfs_access_get_cached(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res, bool may_block)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_access_entry *cache;
@@ -2326,7 +2327,7 @@ out_zap:
        return -ENOENT;
 }
 
-static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
+static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res)
 {
        /* Only check the most recently returned cache entry,
         * but do it without locking.
@@ -2363,15 +2364,17 @@ static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *
        struct rb_node **p = &root_node->rb_node;
        struct rb_node *parent = NULL;
        struct nfs_access_entry *entry;
+       int cmp;
 
        spin_lock(&inode->i_lock);
        while (*p != NULL) {
                parent = *p;
                entry = rb_entry(parent, struct nfs_access_entry, rb_node);
+               cmp = cred_fscmp(set->cred, entry->cred);
 
-               if (set->cred < entry->cred)
+               if (cmp < 0)
                        p = &parent->rb_left;
-               else if (set->cred > entry->cred)
+               else if (cmp > 0)
                        p = &parent->rb_right;
                else
                        goto found;
@@ -2395,7 +2398,7 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
        if (cache == NULL)
                return;
        RB_CLEAR_NODE(&cache->rb_node);
-       cache->cred = get_rpccred(set->cred);
+       cache->cred = get_cred(set->cred);
        cache->mask = set->mask;
 
        /* The above field assignments must be visible
@@ -2459,7 +2462,7 @@ void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
 }
 EXPORT_SYMBOL_GPL(nfs_access_set_mask);
 
-static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
+static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
 {
        struct nfs_access_entry cache;
        bool may_block = (mask & MAY_NOT_BLOCK) == 0;
@@ -2523,7 +2526,7 @@ static int nfs_open_permission_mask(int openflags)
        return mask;
 }
 
-int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
+int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags)
 {
        return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
 }
@@ -2548,7 +2551,7 @@ static int nfs_execute_ok(struct inode *inode, int mask)
 
 int nfs_permission(struct inode *inode, int mask)
 {
-       struct rpc_cred *cred;
+       const struct cred *cred = current_cred();
        int res = 0;
 
        nfs_inc_stats(inode, NFSIOS_VFSACCESS);
@@ -2582,20 +2585,11 @@ force_lookup:
 
        /* Always try fast lookups first */
        rcu_read_lock();
-       cred = rpc_lookup_cred_nonblock();
-       if (!IS_ERR(cred))
-               res = nfs_do_access(inode, cred, mask|MAY_NOT_BLOCK);
-       else
-               res = PTR_ERR(cred);
+       res = nfs_do_access(inode, cred, mask|MAY_NOT_BLOCK);
        rcu_read_unlock();
        if (res == -ECHILD && !(mask & MAY_NOT_BLOCK)) {
                /* Fast lookup failed, try the slow way */
-               cred = rpc_lookup_cred();
-               if (!IS_ERR(cred)) {
-                       res = nfs_do_access(inode, cred, mask);
-                       put_rpccred(cred);
-               } else
-                       res = PTR_ERR(cred);
+               res = nfs_do_access(inode, cred, mask);
        }
 out:
        if (!res && (mask & MAY_EXEC))
index 71bc16225b9817ece6719a687c2c7c18d4ca81ef..f7174f3a9575c19218947c0d3cc4700fa4d7c4d8 100644 (file)
@@ -195,15 +195,20 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
                .access         = entry->mask,
        };
        struct nfs3_accessres   res;
+       struct auth_cred acred = {
+               .cred           = entry->cred,
+       };
        struct rpc_message msg = {
                .rpc_proc       = &nfs3_procedures[NFS3PROC_ACCESS],
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
-               .rpc_cred       = entry->cred,
+               .rpc_cred       = rpc_lookup_generic_cred(&acred, 0, GFP_NOFS),
        };
        int status = -ENOMEM;
 
        dprintk("NFS call  access\n");
+       if (!msg.rpc_cred)
+               goto out;
        res.fattr = nfs_alloc_fattr();
        if (res.fattr == NULL)
                goto out;
@@ -214,6 +219,8 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
                nfs_access_set_mask(entry, res.access);
        nfs_free_fattr(res.fattr);
 out:
+       if (msg.rpc_cred)
+               put_rpccred(msg.rpc_cred);
        dprintk("NFS reply access: %d\n", status);
        return status;
 }
index cafa155a053e1c9bbf7f7b4bb682cc74dfac3794..bf97331c02d335584bb1d796b94325ee9b69d5e2 100644 (file)
@@ -1772,7 +1772,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                rcu_read_unlock();
                nfs_release_seqid(opendata->o_arg.seqid);
                if (!opendata->is_recover) {
-                       ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
+                       ret = nfs_may_open(state->inode, state->owner->so_cred->cr_cred, open_mode);
                        if (ret != 0)
                                goto out;
                }
@@ -2511,7 +2511,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
        } else if ((fmode & FMODE_READ) && !opendata->file_created)
                mask = NFS4_ACCESS_READ;
 
-       cache.cred = cred;
+       cache.cred = cred->cr_cred;
        nfs_access_set_mask(&cache, opendata->o_res.access_result);
        nfs_access_add_cache(state->inode, &cache);
 
@@ -4188,18 +4188,25 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        struct nfs4_accessres res = {
                .server = server,
        };
+       struct auth_cred acred = {
+               .cred = entry->cred,
+       };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
                .rpc_argp = &args,
                .rpc_resp = &res,
-               .rpc_cred = entry->cred,
+               .rpc_cred = rpc_lookup_generic_cred(&acred, 0, GFP_NOFS),
        };
        int status = 0;
 
+       if (!msg.rpc_cred)
+               return -ENOMEM;
        if (!nfs4_have_delegation(inode, FMODE_READ)) {
                res.fattr = nfs_alloc_fattr();
-               if (res.fattr == NULL)
+               if (res.fattr == NULL) {
+                       put_rpccred(msg.rpc_cred);
                        return -ENOMEM;
+               }
                args.bitmask = server->cache_consistency_bitmask;
        }
 
@@ -4210,6 +4217,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                        nfs_refresh_inode(inode, res.fattr);
        }
        nfs_free_fattr(res.fattr);
+       put_rpccred(msg.rpc_cred);
        return status;
 }
 
index ecf22c0034d560d21409bbf916544013cda7234b..7d2064bd421fc3e65c4ea53cb18a5f473feece42 100644 (file)
@@ -51,7 +51,7 @@
 struct nfs_access_entry {
        struct rb_node          rb_node;
        struct list_head        lru;
-       struct rpc_cred *       cred;
+       const struct cred *     cred;
        __u32                   mask;
        struct rcu_head         rcu_head;
 };
@@ -491,7 +491,7 @@ extern const struct dentry_operations nfs_dentry_operations;
 extern void nfs_force_lookup_revalidate(struct inode *dir);
 extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
                        struct nfs_fattr *fattr, struct nfs4_label *label);
-extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
+extern int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags);
 extern void nfs_access_zap_cache(struct inode *inode);
 
 /*