Skip to content

Commit 6238aec

Browse files
neilbrownamschuma-ntap
authored andcommitted
NFS: don't store 'struct cred *' in struct nfs_access_entry
Storing the 'struct cred *' in nfs_access_entry is problematic. An active 'cred' can keep a 'struct key *' active, and a quota is imposed on the number of such keys that a user can maintain. Cached 'nfs_access_entry' structs have indefinite lifetime, and having these keep 'struct key's alive imposes on that quota. So remove the 'struct cred *' and replace it with the fields we need: kuid_t, kgid_t, and struct group_info * This makes the 'struct nfs_access_entry' 64 bits larger. New function "access_cmp" is introduced which is identical to cred_fscmp() except that the second arg is an 'nfs_access_entry', rather than a 'cred' Fixes: b68572e ("NFS: change access cache to use 'struct cred'.") Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
1 parent 73fbb3f commit 6238aec

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

fs/nfs/dir.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,7 +2528,7 @@ MODULE_PARM_DESC(nfs_access_max_cachesize, "NFS access maximum total cache lengt
25282528

25292529
static void nfs_access_free_entry(struct nfs_access_entry *entry)
25302530
{
2531-
put_cred(entry->cred);
2531+
put_group_info(entry->group_info);
25322532
kfree_rcu(entry, rcu_head);
25332533
smp_mb__before_atomic();
25342534
atomic_long_dec(&nfs_access_nr_entries);
@@ -2654,14 +2654,51 @@ void nfs_access_zap_cache(struct inode *inode)
26542654
}
26552655
EXPORT_SYMBOL_GPL(nfs_access_zap_cache);
26562656

2657+
static int access_cmp(const struct cred *a, const struct nfs_access_entry *b)
2658+
{
2659+
struct group_info *ga, *gb;
2660+
int g;
2661+
2662+
if (uid_lt(a->fsuid, b->fsuid))
2663+
return -1;
2664+
if (uid_gt(a->fsuid, b->fsuid))
2665+
return 1;
2666+
2667+
if (gid_lt(a->fsgid, b->fsgid))
2668+
return -1;
2669+
if (gid_gt(a->fsgid, b->fsgid))
2670+
return 1;
2671+
2672+
ga = a->group_info;
2673+
gb = b->group_info;
2674+
if (ga == gb)
2675+
return 0;
2676+
if (ga == NULL)
2677+
return -1;
2678+
if (gb == NULL)
2679+
return 1;
2680+
if (ga->ngroups < gb->ngroups)
2681+
return -1;
2682+
if (ga->ngroups > gb->ngroups)
2683+
return 1;
2684+
2685+
for (g = 0; g < ga->ngroups; g++) {
2686+
if (gid_lt(ga->gid[g], gb->gid[g]))
2687+
return -1;
2688+
if (gid_gt(ga->gid[g], gb->gid[g]))
2689+
return 1;
2690+
}
2691+
return 0;
2692+
}
2693+
26572694
static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
26582695
{
26592696
struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
26602697

26612698
while (n != NULL) {
26622699
struct nfs_access_entry *entry =
26632700
rb_entry(n, struct nfs_access_entry, rb_node);
2664-
int cmp = cred_fscmp(cred, entry->cred);
2701+
int cmp = access_cmp(cred, entry);
26652702

26662703
if (cmp < 0)
26672704
n = n->rb_left;
@@ -2731,7 +2768,7 @@ static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cre
27312768
lh = rcu_dereference(list_tail_rcu(&nfsi->access_cache_entry_lru));
27322769
cache = list_entry(lh, struct nfs_access_entry, lru);
27332770
if (lh == &nfsi->access_cache_entry_lru ||
2734-
cred_fscmp(cred, cache->cred) != 0)
2771+
access_cmp(cred, cache) != 0)
27352772
cache = NULL;
27362773
if (cache == NULL)
27372774
goto out;
@@ -2773,7 +2810,7 @@ static void nfs_access_add_rbtree(struct inode *inode,
27732810
while (*p != NULL) {
27742811
parent = *p;
27752812
entry = rb_entry(parent, struct nfs_access_entry, rb_node);
2776-
cmp = cred_fscmp(cred, entry->cred);
2813+
cmp = access_cmp(cred, entry);
27772814

27782815
if (cmp < 0)
27792816
p = &parent->rb_left;
@@ -2802,7 +2839,9 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set,
28022839
if (cache == NULL)
28032840
return;
28042841
RB_CLEAR_NODE(&cache->rb_node);
2805-
cache->cred = get_cred(cred);
2842+
cache->fsuid = cred->fsuid;
2843+
cache->fsgid = cred->fsgid;
2844+
cache->group_info = get_group_info(cred->group_info);
28062845
cache->mask = set->mask;
28072846

28082847
/* The above field assignments must be visible
@@ -2895,7 +2934,6 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
28952934
cache.mask |= NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
28962935
else
28972936
cache.mask |= NFS_ACCESS_EXECUTE;
2898-
cache.cred = cred;
28992937
status = NFS_PROTO(inode)->access(inode, &cache, cred);
29002938
if (status != 0) {
29012939
if (status == -ESTALE) {

fs/nfs/nfs4proc.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2653,7 +2653,6 @@ static int nfs4_opendata_access(const struct cred *cred,
26532653
} else if ((fmode & FMODE_READ) && !opendata->file_created)
26542654
mask = NFS4_ACCESS_READ;
26552655

2656-
cache.cred = cred;
26572656
nfs_access_set_mask(&cache, opendata->o_res.access_result);
26582657
nfs_access_add_cache(state->inode, &cache, cred);
26592658

include/linux/nfs_fs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@
6161
struct nfs_access_entry {
6262
struct rb_node rb_node;
6363
struct list_head lru;
64-
const struct cred * cred;
64+
kuid_t fsuid;
65+
kgid_t fsgid;
66+
struct group_info *group_info;
6567
__u32 mask;
6668
struct rcu_head rcu_head;
6769
};

0 commit comments

Comments
 (0)