1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * NFS exporting and validation.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * We maintain a list of clients, each of which has a list of
61da177e4SLinus Torvalds * exports. To export an fs to a given client, you first have
71da177e4SLinus Torvalds * to create the client entry with NFSCTL_ADDCLIENT, which
81da177e4SLinus Torvalds * creates a client control block and adds it to the hash
91da177e4SLinus Torvalds * table. Then, you call NFSCTL_EXPORT for each fs.
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds *
121da177e4SLinus Torvalds * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
131da177e4SLinus Torvalds */
141da177e4SLinus Torvalds
155a0e3ad6STejun Heo #include <linux/slab.h>
161da177e4SLinus Torvalds #include <linux/namei.h>
17f35279d3SBruce Allan #include <linux/module.h>
18a5694255SChristoph Hellwig #include <linux/exportfs.h>
19b3853e0eSStanislav Kinsbursky #include <linux/sunrpc/svc_xprt.h>
201da177e4SLinus Torvalds
219a74af21SBoaz Harrosh #include "nfsd.h"
221557aca7SJ. Bruce Fields #include "nfsfh.h"
23b3853e0eSStanislav Kinsbursky #include "netns.h"
249cf514ccSChristoph Hellwig #include "pnfs.h"
2565294c1fSJeff Layton #include "filecache.h"
26cf749f3cSTrond Myklebust #include "trace.h"
279a74af21SBoaz Harrosh
281da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_EXPORT
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds * We have two caches.
321da177e4SLinus Torvalds * One maps client+vfsmnt+dentry to export options - the export map
331da177e4SLinus Torvalds * The other maps client+filehandle-fragment to export options. - the expkey map
341da177e4SLinus Torvalds *
351da177e4SLinus Torvalds * The export options are actually stored in the first map, and the
361da177e4SLinus Torvalds * second map contains a reference to the entry in the first map.
371da177e4SLinus Torvalds */
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds #define EXPKEY_HASHBITS 8
401da177e4SLinus Torvalds #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
411da177e4SLinus Torvalds #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
421da177e4SLinus Torvalds
expkey_put(struct kref * ref)43*48830406SYang Erkun static void expkey_put(struct kref *ref)
441da177e4SLinus Torvalds {
45*48830406SYang Erkun struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
46baab935fSNeilBrown
47baab935fSNeilBrown if (test_bit(CACHE_VALID, &key->h.flags) &&
48e83aece3SJan Blunck !test_bit(CACHE_NEGATIVE, &key->h.flags))
49e83aece3SJan Blunck path_put(&key->ek_path);
501da177e4SLinus Torvalds auth_domain_put(key->ek_client);
51*48830406SYang Erkun kfree_rcu(key, ek_rcu);
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds
expkey_upcall(struct cache_detail * cd,struct cache_head * h)5465286b88STrond Myklebust static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
5565286b88STrond Myklebust {
5665286b88STrond Myklebust return sunrpc_cache_pipe_upcall(cd, h);
5765286b88STrond Myklebust }
5865286b88STrond Myklebust
expkey_request(struct cache_detail * cd,struct cache_head * h,char ** bpp,int * blen)591da177e4SLinus Torvalds static void expkey_request(struct cache_detail *cd,
601da177e4SLinus Torvalds struct cache_head *h,
611da177e4SLinus Torvalds char **bpp, int *blen)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds /* client fsidtype \xfsid */
641da177e4SLinus Torvalds struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
651da177e4SLinus Torvalds char type[5];
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds qword_add(bpp, blen, ek->ek_client->name);
681da177e4SLinus Torvalds snprintf(type, 5, "%d", ek->ek_fsidtype);
691da177e4SLinus Torvalds qword_add(bpp, blen, type);
701da177e4SLinus Torvalds qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
711da177e4SLinus Torvalds (*bpp)[-1] = '\n';
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds
74c89172e3SStanislav Kinsbursky static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
75c89172e3SStanislav Kinsbursky struct svc_expkey *old);
76c89172e3SStanislav Kinsbursky static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
7774cae61aSAdrian Bunk
expkey_parse(struct cache_detail * cd,char * mesg,int mlen)781da177e4SLinus Torvalds static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
791da177e4SLinus Torvalds {
80f0db79d5SKinglong Mee /* client fsidtype fsid expiry [path] */
811da177e4SLinus Torvalds char *buf;
821da177e4SLinus Torvalds int len;
831da177e4SLinus Torvalds struct auth_domain *dom = NULL;
841da177e4SLinus Torvalds int err;
851da177e4SLinus Torvalds int fsidtype;
861da177e4SLinus Torvalds char *ep;
871da177e4SLinus Torvalds struct svc_expkey key;
8830bc4dfdSJ. Bruce Fields struct svc_expkey *ek = NULL;
891da177e4SLinus Torvalds
903476964dSDan Carpenter if (mesg[mlen - 1] != '\n')
911da177e4SLinus Torvalds return -EINVAL;
921da177e4SLinus Torvalds mesg[mlen-1] = 0;
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
951da177e4SLinus Torvalds err = -ENOMEM;
9630bc4dfdSJ. Bruce Fields if (!buf)
9730bc4dfdSJ. Bruce Fields goto out;
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds err = -EINVAL;
10075bfb704SColin Ian King if (qword_get(&mesg, buf, PAGE_SIZE) <= 0)
1011da177e4SLinus Torvalds goto out;
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds err = -ENOENT;
1041da177e4SLinus Torvalds dom = auth_domain_find(buf);
1051da177e4SLinus Torvalds if (!dom)
1061da177e4SLinus Torvalds goto out;
1071da177e4SLinus Torvalds dprintk("found domain %s\n", buf);
1081da177e4SLinus Torvalds
1091da177e4SLinus Torvalds err = -EINVAL;
11075bfb704SColin Ian King if (qword_get(&mesg, buf, PAGE_SIZE) <= 0)
1111da177e4SLinus Torvalds goto out;
1121da177e4SLinus Torvalds fsidtype = simple_strtoul(buf, &ep, 10);
1131da177e4SLinus Torvalds if (*ep)
1141da177e4SLinus Torvalds goto out;
1151da177e4SLinus Torvalds dprintk("found fsidtype %d\n", fsidtype);
1164bdff8c0SFrank Filz if (key_len(fsidtype)==0) /* invalid type */
1171da177e4SLinus Torvalds goto out;
1181da177e4SLinus Torvalds if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
1191da177e4SLinus Torvalds goto out;
1201da177e4SLinus Torvalds dprintk("found fsid length %d\n", len);
1211da177e4SLinus Torvalds if (len != key_len(fsidtype))
1221da177e4SLinus Torvalds goto out;
1231da177e4SLinus Torvalds
1241da177e4SLinus Torvalds /* OK, we seem to have a valid key */
1251da177e4SLinus Torvalds key.h.flags = 0;
126cf64b9bcSNeilBrown err = get_expiry(&mesg, &key.h.expiry_time);
127cf64b9bcSNeilBrown if (err)
1281da177e4SLinus Torvalds goto out;
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds key.ek_client = dom;
1311da177e4SLinus Torvalds key.ek_fsidtype = fsidtype;
1321da177e4SLinus Torvalds memcpy(key.ek_fsid, buf, len);
1331da177e4SLinus Torvalds
134c89172e3SStanislav Kinsbursky ek = svc_expkey_lookup(cd, &key);
1358d270f7fSNeilBrown err = -ENOMEM;
1368d270f7fSNeilBrown if (!ek)
1378d270f7fSNeilBrown goto out;
1388d270f7fSNeilBrown
1391da177e4SLinus Torvalds /* now we want a pathname, or empty meaning NEGATIVE */
1408d270f7fSNeilBrown err = -EINVAL;
14130bc4dfdSJ. Bruce Fields len = qword_get(&mesg, buf, PAGE_SIZE);
14230bc4dfdSJ. Bruce Fields if (len < 0)
1431da177e4SLinus Torvalds goto out;
1441da177e4SLinus Torvalds dprintk("Path seems to be <%s>\n", buf);
1451da177e4SLinus Torvalds err = 0;
1461da177e4SLinus Torvalds if (len == 0) {
1471da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &key.h.flags);
148c89172e3SStanislav Kinsbursky ek = svc_expkey_update(cd, &key, ek);
1496a30e47fSTrond Myklebust if (ek)
1506a30e47fSTrond Myklebust trace_nfsd_expkey_update(ek, NULL);
1516a30e47fSTrond Myklebust else
15230bc4dfdSJ. Bruce Fields err = -ENOMEM;
1531da177e4SLinus Torvalds } else {
154a63bb996SAl Viro err = kern_path(buf, 0, &key.ek_path);
15530bc4dfdSJ. Bruce Fields if (err)
1561da177e4SLinus Torvalds goto out;
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds dprintk("Found the path %s\n", buf);
1591da177e4SLinus Torvalds
160c89172e3SStanislav Kinsbursky ek = svc_expkey_update(cd, &key, ek);
1616a30e47fSTrond Myklebust if (ek)
1626a30e47fSTrond Myklebust trace_nfsd_expkey_update(ek, buf);
1636a30e47fSTrond Myklebust else
1648d270f7fSNeilBrown err = -ENOMEM;
165a63bb996SAl Viro path_put(&key.ek_path);
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds cache_flush();
1681da177e4SLinus Torvalds out:
16930bc4dfdSJ. Bruce Fields if (ek)
170d4bb527eSStanislav Kinsbursky cache_put(&ek->h, cd);
1711da177e4SLinus Torvalds if (dom)
1721da177e4SLinus Torvalds auth_domain_put(dom);
1731da177e4SLinus Torvalds kfree(buf);
1741da177e4SLinus Torvalds return err;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds
expkey_show(struct seq_file * m,struct cache_detail * cd,struct cache_head * h)1771da177e4SLinus Torvalds static int expkey_show(struct seq_file *m,
1781da177e4SLinus Torvalds struct cache_detail *cd,
1791da177e4SLinus Torvalds struct cache_head *h)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds struct svc_expkey *ek ;
182af6a4e28SNeilBrown int i;
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds if (h ==NULL) {
1851da177e4SLinus Torvalds seq_puts(m, "#domain fsidtype fsid [path]\n");
1861da177e4SLinus Torvalds return 0;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds ek = container_of(h, struct svc_expkey, h);
189af6a4e28SNeilBrown seq_printf(m, "%s %d 0x", ek->ek_client->name,
190af6a4e28SNeilBrown ek->ek_fsidtype);
191af6a4e28SNeilBrown for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
192af6a4e28SNeilBrown seq_printf(m, "%08x", ek->ek_fsid[i]);
1931da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags) &&
1941da177e4SLinus Torvalds !test_bit(CACHE_NEGATIVE, &h->flags)) {
1951da177e4SLinus Torvalds seq_printf(m, " ");
196c32c2f63SJan Blunck seq_path(m, &ek->ek_path, "\\ \t\n");
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds seq_printf(m, "\n");
1991da177e4SLinus Torvalds return 0;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
expkey_match(struct cache_head * a,struct cache_head * b)2028d270f7fSNeilBrown static inline int expkey_match (struct cache_head *a, struct cache_head *b)
2038d270f7fSNeilBrown {
2048d270f7fSNeilBrown struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
2058d270f7fSNeilBrown struct svc_expkey *new = container_of(b, struct svc_expkey, h);
2068d270f7fSNeilBrown
2078d270f7fSNeilBrown if (orig->ek_fsidtype != new->ek_fsidtype ||
2088d270f7fSNeilBrown orig->ek_client != new->ek_client ||
2098d270f7fSNeilBrown memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
2108d270f7fSNeilBrown return 0;
2118d270f7fSNeilBrown return 1;
2128d270f7fSNeilBrown }
2138d270f7fSNeilBrown
expkey_init(struct cache_head * cnew,struct cache_head * citem)2148d270f7fSNeilBrown static inline void expkey_init(struct cache_head *cnew,
2158d270f7fSNeilBrown struct cache_head *citem)
2168d270f7fSNeilBrown {
2178d270f7fSNeilBrown struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
2188d270f7fSNeilBrown struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
2198d270f7fSNeilBrown
2208d270f7fSNeilBrown kref_get(&item->ek_client->ref);
2218d270f7fSNeilBrown new->ek_client = item->ek_client;
2228d270f7fSNeilBrown new->ek_fsidtype = item->ek_fsidtype;
223af6a4e28SNeilBrown
224af6a4e28SNeilBrown memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
2258d270f7fSNeilBrown }
2268d270f7fSNeilBrown
expkey_update(struct cache_head * cnew,struct cache_head * citem)2278d270f7fSNeilBrown static inline void expkey_update(struct cache_head *cnew,
2288d270f7fSNeilBrown struct cache_head *citem)
2298d270f7fSNeilBrown {
2308d270f7fSNeilBrown struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
2318d270f7fSNeilBrown struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
2328d270f7fSNeilBrown
233e83aece3SJan Blunck new->ek_path = item->ek_path;
234e83aece3SJan Blunck path_get(&item->ek_path);
2358d270f7fSNeilBrown }
2368d270f7fSNeilBrown
expkey_alloc(void)2378d270f7fSNeilBrown static struct cache_head *expkey_alloc(void)
2388d270f7fSNeilBrown {
2398d270f7fSNeilBrown struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
2408d270f7fSNeilBrown if (i)
2418d270f7fSNeilBrown return &i->h;
2428d270f7fSNeilBrown else
2438d270f7fSNeilBrown return NULL;
2448d270f7fSNeilBrown }
2458d270f7fSNeilBrown
expkey_flush(void)24665294c1fSJeff Layton static void expkey_flush(void)
24765294c1fSJeff Layton {
24865294c1fSJeff Layton /*
24965294c1fSJeff Layton * Take the nfsd_mutex here to ensure that the file cache is not
25065294c1fSJeff Layton * destroyed while we're in the middle of flushing.
25165294c1fSJeff Layton */
25265294c1fSJeff Layton mutex_lock(&nfsd_mutex);
2535e113224STrond Myklebust nfsd_file_cache_purge(current->nsproxy->net_ns);
25465294c1fSJeff Layton mutex_unlock(&nfsd_mutex);
25565294c1fSJeff Layton }
25665294c1fSJeff Layton
257ae2e408eSBhumika Goyal static const struct cache_detail svc_expkey_cache_template = {
258f35279d3SBruce Allan .owner = THIS_MODULE,
2591da177e4SLinus Torvalds .hash_size = EXPKEY_HASHMAX,
2601da177e4SLinus Torvalds .name = "nfsd.fh",
2611da177e4SLinus Torvalds .cache_put = expkey_put,
26265286b88STrond Myklebust .cache_upcall = expkey_upcall,
26373fb847aSStanislav Kinsbursky .cache_request = expkey_request,
2641da177e4SLinus Torvalds .cache_parse = expkey_parse,
2651da177e4SLinus Torvalds .cache_show = expkey_show,
2668d270f7fSNeilBrown .match = expkey_match,
2678d270f7fSNeilBrown .init = expkey_init,
2688d270f7fSNeilBrown .update = expkey_update,
2698d270f7fSNeilBrown .alloc = expkey_alloc,
27065294c1fSJeff Layton .flush = expkey_flush,
2711da177e4SLinus Torvalds };
2721da177e4SLinus Torvalds
27361f8603dSNeilBrown static int
svc_expkey_hash(struct svc_expkey * item)27461f8603dSNeilBrown svc_expkey_hash(struct svc_expkey *item)
2751da177e4SLinus Torvalds {
2768d270f7fSNeilBrown int hash = item->ek_fsidtype;
2778d270f7fSNeilBrown char * cp = (char*)item->ek_fsid;
2788d270f7fSNeilBrown int len = key_len(item->ek_fsidtype);
2798d270f7fSNeilBrown
2808d270f7fSNeilBrown hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
2818d270f7fSNeilBrown hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
2828d270f7fSNeilBrown hash &= EXPKEY_HASHMASK;
28361f8603dSNeilBrown return hash;
28461f8603dSNeilBrown }
28561f8603dSNeilBrown
28661f8603dSNeilBrown static struct svc_expkey *
svc_expkey_lookup(struct cache_detail * cd,struct svc_expkey * item)287c89172e3SStanislav Kinsbursky svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
28861f8603dSNeilBrown {
28961f8603dSNeilBrown struct cache_head *ch;
29061f8603dSNeilBrown int hash = svc_expkey_hash(item);
2918d270f7fSNeilBrown
2929ceddd9dSTrond Myklebust ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash);
2938d270f7fSNeilBrown if (ch)
2948d270f7fSNeilBrown return container_of(ch, struct svc_expkey, h);
2958d270f7fSNeilBrown else
2968d270f7fSNeilBrown return NULL;
2971da177e4SLinus Torvalds }
2981da177e4SLinus Torvalds
2998d270f7fSNeilBrown static struct svc_expkey *
svc_expkey_update(struct cache_detail * cd,struct svc_expkey * new,struct svc_expkey * old)300c89172e3SStanislav Kinsbursky svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
301c89172e3SStanislav Kinsbursky struct svc_expkey *old)
3021da177e4SLinus Torvalds {
3038d270f7fSNeilBrown struct cache_head *ch;
30461f8603dSNeilBrown int hash = svc_expkey_hash(new);
3058d270f7fSNeilBrown
306c89172e3SStanislav Kinsbursky ch = sunrpc_cache_update(cd, &new->h, &old->h, hash);
3078d270f7fSNeilBrown if (ch)
3088d270f7fSNeilBrown return container_of(ch, struct svc_expkey, h);
3098d270f7fSNeilBrown else
3108d270f7fSNeilBrown return NULL;
3111da177e4SLinus Torvalds }
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds
3141da177e4SLinus Torvalds #define EXPORT_HASHBITS 8
3151da177e4SLinus Torvalds #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
3161da177e4SLinus Torvalds
nfsd4_fslocs_free(struct nfsd4_fs_locations * fsloc)31793346919SManoj Naik static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
31893346919SManoj Naik {
319a1f05514SKinglong Mee struct nfsd4_fs_location *locations = fsloc->locations;
32093346919SManoj Naik int i;
32193346919SManoj Naik
322a1f05514SKinglong Mee if (!locations)
323a1f05514SKinglong Mee return;
324a1f05514SKinglong Mee
32593346919SManoj Naik for (i = 0; i < fsloc->locations_count; i++) {
326a1f05514SKinglong Mee kfree(locations[i].path);
327a1f05514SKinglong Mee kfree(locations[i].hosts);
32893346919SManoj Naik }
329a1f05514SKinglong Mee
330a1f05514SKinglong Mee kfree(locations);
331a1f05514SKinglong Mee fsloc->locations = NULL;
33293346919SManoj Naik }
33393346919SManoj Naik
export_stats_init(struct export_stats * stats)33420ad856eSAmir Goldstein static int export_stats_init(struct export_stats *stats)
33520ad856eSAmir Goldstein {
33620ad856eSAmir Goldstein stats->start_time = ktime_get_seconds();
33720ad856eSAmir Goldstein return nfsd_percpu_counters_init(stats->counter, EXP_STATS_COUNTERS_NUM);
33820ad856eSAmir Goldstein }
33920ad856eSAmir Goldstein
export_stats_reset(struct export_stats * stats)34020ad856eSAmir Goldstein static void export_stats_reset(struct export_stats *stats)
34120ad856eSAmir Goldstein {
3429b31d561SChuck Lever if (stats)
3439b31d561SChuck Lever nfsd_percpu_counters_reset(stats->counter,
3449b31d561SChuck Lever EXP_STATS_COUNTERS_NUM);
34520ad856eSAmir Goldstein }
34620ad856eSAmir Goldstein
export_stats_destroy(struct export_stats * stats)34720ad856eSAmir Goldstein static void export_stats_destroy(struct export_stats *stats)
34820ad856eSAmir Goldstein {
3499b31d561SChuck Lever if (stats)
3509b31d561SChuck Lever nfsd_percpu_counters_destroy(stats->counter,
3519b31d561SChuck Lever EXP_STATS_COUNTERS_NUM);
35220ad856eSAmir Goldstein }
35320ad856eSAmir Goldstein
svc_export_put(struct kref * ref)354*48830406SYang Erkun static void svc_export_put(struct kref *ref)
3551da177e4SLinus Torvalds {
356*48830406SYang Erkun struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
35754775491SJan Blunck path_put(&exp->ex_path);
3581da177e4SLinus Torvalds auth_domain_put(exp->ex_client);
35993346919SManoj Naik nfsd4_fslocs_free(&exp->ex_fslocs);
3609b31d561SChuck Lever export_stats_destroy(exp->ex_stats);
3619b31d561SChuck Lever kfree(exp->ex_stats);
362885c91f7Smajianpeng kfree(exp->ex_uuid);
363*48830406SYang Erkun kfree_rcu(exp, ex_rcu);
3641da177e4SLinus Torvalds }
3651da177e4SLinus Torvalds
svc_export_upcall(struct cache_detail * cd,struct cache_head * h)36665286b88STrond Myklebust static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
36765286b88STrond Myklebust {
36865286b88STrond Myklebust return sunrpc_cache_pipe_upcall(cd, h);
36965286b88STrond Myklebust }
37065286b88STrond Myklebust
svc_export_request(struct cache_detail * cd,struct cache_head * h,char ** bpp,int * blen)3711da177e4SLinus Torvalds static void svc_export_request(struct cache_detail *cd,
3721da177e4SLinus Torvalds struct cache_head *h,
3731da177e4SLinus Torvalds char **bpp, int *blen)
3741da177e4SLinus Torvalds {
3751da177e4SLinus Torvalds /* client path */
3761da177e4SLinus Torvalds struct svc_export *exp = container_of(h, struct svc_export, h);
3771da177e4SLinus Torvalds char *pth;
3781da177e4SLinus Torvalds
3791da177e4SLinus Torvalds qword_add(bpp, blen, exp->ex_client->name);
380cf28b486SJan Blunck pth = d_path(&exp->ex_path, *bpp, *blen);
3811da177e4SLinus Torvalds if (IS_ERR(pth)) {
3821da177e4SLinus Torvalds /* is this correct? */
3831da177e4SLinus Torvalds (*bpp)[0] = '\n';
3841da177e4SLinus Torvalds return;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds qword_add(bpp, blen, pth);
3871da177e4SLinus Torvalds (*bpp)[-1] = '\n';
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds
39074cae61aSAdrian Bunk static struct svc_export *svc_export_update(struct svc_export *new,
39174cae61aSAdrian Bunk struct svc_export *old);
3924f7774c3SNeilBrown static struct svc_export *svc_export_lookup(struct svc_export *);
3931da177e4SLinus Torvalds
check_export(struct path * path,int * flags,unsigned char * uuid)394899bf2ceSChristian Brauner static int check_export(struct path *path, int *flags, unsigned char *uuid)
3951da177e4SLinus Torvalds {
396899bf2ceSChristian Brauner struct inode *inode = d_inode(path->dentry);
3971da177e4SLinus Torvalds
398f2ca7153SJ. Bruce Fields /*
399f2ca7153SJ. Bruce Fields * We currently export only dirs, regular files, and (for v4
400f2ca7153SJ. Bruce Fields * pseudoroot) symlinks.
4011da177e4SLinus Torvalds */
4021da177e4SLinus Torvalds if (!S_ISDIR(inode->i_mode) &&
403f2ca7153SJ. Bruce Fields !S_ISLNK(inode->i_mode) &&
4041da177e4SLinus Torvalds !S_ISREG(inode->i_mode))
4051da177e4SLinus Torvalds return -ENOTDIR;
4061da177e4SLinus Torvalds
407774b1478SJ. Bruce Fields /*
408774b1478SJ. Bruce Fields * Mountd should never pass down a writeable V4ROOT export, but,
409774b1478SJ. Bruce Fields * just to make sure:
410774b1478SJ. Bruce Fields */
411774b1478SJ. Bruce Fields if (*flags & NFSEXP_V4ROOT)
412774b1478SJ. Bruce Fields *flags |= NFSEXP_READONLY;
413774b1478SJ. Bruce Fields
4141da177e4SLinus Torvalds /* There are two requirements on a filesystem to be exportable.
4151da177e4SLinus Torvalds * 1: We must be able to identify the filesystem from a number.
4161da177e4SLinus Torvalds * either a device number (so FS_REQUIRES_DEV needed)
417af6a4e28SNeilBrown * or an FSID number (so NFSEXP_FSID or ->uuid is needed).
4181da177e4SLinus Torvalds * 2: We must be able to find an inode from a filehandle.
4191da177e4SLinus Torvalds * This means that s_export_op must be set.
420899bf2ceSChristian Brauner * 3: We must not currently be on an idmapped mount.
4211da177e4SLinus Torvalds */
4221da177e4SLinus Torvalds if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
423774b1478SJ. Bruce Fields !(*flags & NFSEXP_FSID) &&
424af6a4e28SNeilBrown uuid == NULL) {
4253e3b4800SGreg Banks dprintk("exp_export: export of non-dev fs without fsid\n");
4261da177e4SLinus Torvalds return -EINVAL;
4271da177e4SLinus Torvalds }
428cfaea787SChristoph Hellwig
429cfaea787SChristoph Hellwig if (!inode->i_sb->s_export_op ||
430cfaea787SChristoph Hellwig !inode->i_sb->s_export_op->fh_to_dentry) {
4311da177e4SLinus Torvalds dprintk("exp_export: export of invalid fs type.\n");
4321da177e4SLinus Torvalds return -EINVAL;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds
435bb49e9e7SChristian Brauner if (is_idmapped_mnt(path->mnt)) {
436899bf2ceSChristian Brauner dprintk("exp_export: export of idmapped mounts not yet supported.\n");
437899bf2ceSChristian Brauner return -EINVAL;
438899bf2ceSChristian Brauner }
439899bf2ceSChristian Brauner
440ba5e8187SJeff Layton if (inode->i_sb->s_export_op->flags & EXPORT_OP_NOSUBTREECHK &&
441ba5e8187SJeff Layton !(*flags & NFSEXP_NOSUBTREECHECK)) {
442ba5e8187SJeff Layton dprintk("%s: %s does not support subtree checking!\n",
443ba5e8187SJeff Layton __func__, inode->i_sb->s_type->name);
444ba5e8187SJeff Layton return -EINVAL;
445ba5e8187SJeff Layton }
4461da177e4SLinus Torvalds return 0;
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds
44993346919SManoj Naik #ifdef CONFIG_NFSD_V4
45093346919SManoj Naik
45193346919SManoj Naik static int
fsloc_parse(char ** mesg,char * buf,struct nfsd4_fs_locations * fsloc)45293346919SManoj Naik fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
45393346919SManoj Naik {
45493346919SManoj Naik int len;
45593346919SManoj Naik int migrated, i, err;
45693346919SManoj Naik
457be69da80SKinglong Mee /* more than one fsloc */
458be69da80SKinglong Mee if (fsloc->locations)
459be69da80SKinglong Mee return -EINVAL;
460be69da80SKinglong Mee
46193346919SManoj Naik /* listsize */
462a007c4c3SJ. Bruce Fields err = get_uint(mesg, &fsloc->locations_count);
46393346919SManoj Naik if (err)
46493346919SManoj Naik return err;
46593346919SManoj Naik if (fsloc->locations_count > MAX_FS_LOCATIONS)
46693346919SManoj Naik return -EINVAL;
46793346919SManoj Naik if (fsloc->locations_count == 0)
46893346919SManoj Naik return 0;
46993346919SManoj Naik
4706396bb22SKees Cook fsloc->locations = kcalloc(fsloc->locations_count,
4716396bb22SKees Cook sizeof(struct nfsd4_fs_location),
4726396bb22SKees Cook GFP_KERNEL);
47393346919SManoj Naik if (!fsloc->locations)
47493346919SManoj Naik return -ENOMEM;
47593346919SManoj Naik for (i=0; i < fsloc->locations_count; i++) {
47693346919SManoj Naik /* colon separated host list */
47793346919SManoj Naik err = -EINVAL;
47893346919SManoj Naik len = qword_get(mesg, buf, PAGE_SIZE);
47993346919SManoj Naik if (len <= 0)
48093346919SManoj Naik goto out_free_all;
48193346919SManoj Naik err = -ENOMEM;
48293346919SManoj Naik fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
48393346919SManoj Naik if (!fsloc->locations[i].hosts)
48493346919SManoj Naik goto out_free_all;
48593346919SManoj Naik err = -EINVAL;
48693346919SManoj Naik /* slash separated path component list */
48793346919SManoj Naik len = qword_get(mesg, buf, PAGE_SIZE);
48893346919SManoj Naik if (len <= 0)
48993346919SManoj Naik goto out_free_all;
49093346919SManoj Naik err = -ENOMEM;
49193346919SManoj Naik fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
49293346919SManoj Naik if (!fsloc->locations[i].path)
49393346919SManoj Naik goto out_free_all;
49493346919SManoj Naik }
49593346919SManoj Naik /* migrated */
49693346919SManoj Naik err = get_int(mesg, &migrated);
49793346919SManoj Naik if (err)
49893346919SManoj Naik goto out_free_all;
49993346919SManoj Naik err = -EINVAL;
50093346919SManoj Naik if (migrated < 0 || migrated > 1)
50193346919SManoj Naik goto out_free_all;
50293346919SManoj Naik fsloc->migrated = migrated;
50393346919SManoj Naik return 0;
50493346919SManoj Naik out_free_all:
50593346919SManoj Naik nfsd4_fslocs_free(fsloc);
50693346919SManoj Naik return err;
50793346919SManoj Naik }
50893346919SManoj Naik
secinfo_parse(char ** mesg,char * buf,struct svc_export * exp)509e677bfe4SAndy Adamson static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
510e677bfe4SAndy Adamson {
511e677bfe4SAndy Adamson struct exp_flavor_info *f;
5121f53146dSKinglong Mee u32 listsize;
5131f53146dSKinglong Mee int err;
514e677bfe4SAndy Adamson
515be69da80SKinglong Mee /* more than one secinfo */
516be69da80SKinglong Mee if (exp->ex_nflavors)
517be69da80SKinglong Mee return -EINVAL;
518be69da80SKinglong Mee
5191f53146dSKinglong Mee err = get_uint(mesg, &listsize);
520e677bfe4SAndy Adamson if (err)
521e677bfe4SAndy Adamson return err;
5221f53146dSKinglong Mee if (listsize > MAX_SECINFO_LIST)
523e677bfe4SAndy Adamson return -EINVAL;
524e677bfe4SAndy Adamson
525e677bfe4SAndy Adamson for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
526a007c4c3SJ. Bruce Fields err = get_uint(mesg, &f->pseudoflavor);
527e677bfe4SAndy Adamson if (err)
528e677bfe4SAndy Adamson return err;
529e677bfe4SAndy Adamson /*
53080492e7dSRoel Kluin * XXX: It would be nice to also check whether this
53180492e7dSRoel Kluin * pseudoflavor is supported, so we can discover the
53280492e7dSRoel Kluin * problem at export time instead of when a client fails
53380492e7dSRoel Kluin * to authenticate.
534e677bfe4SAndy Adamson */
535a007c4c3SJ. Bruce Fields err = get_uint(mesg, &f->flags);
536e677bfe4SAndy Adamson if (err)
537e677bfe4SAndy Adamson return err;
538e677bfe4SAndy Adamson /* Only some flags are allowed to differ between flavors: */
539e677bfe4SAndy Adamson if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
540e677bfe4SAndy Adamson return -EINVAL;
541e677bfe4SAndy Adamson }
542e677bfe4SAndy Adamson exp->ex_nflavors = listsize;
543e677bfe4SAndy Adamson return 0;
544e677bfe4SAndy Adamson }
545e677bfe4SAndy Adamson
54693346919SManoj Naik #else /* CONFIG_NFSD_V4 */
547e677bfe4SAndy Adamson static inline int
fsloc_parse(char ** mesg,char * buf,struct nfsd4_fs_locations * fsloc)548e677bfe4SAndy Adamson fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
549e677bfe4SAndy Adamson static inline int
secinfo_parse(char ** mesg,char * buf,struct svc_export * exp)550e677bfe4SAndy Adamson secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
55193346919SManoj Naik #endif
55293346919SManoj Naik
xprtsec_parse(char ** mesg,char * buf,struct svc_export * exp)5539280c577SChuck Lever static int xprtsec_parse(char **mesg, char *buf, struct svc_export *exp)
5549280c577SChuck Lever {
5559280c577SChuck Lever unsigned int i, mode, listsize;
5569280c577SChuck Lever int err;
5579280c577SChuck Lever
5589280c577SChuck Lever err = get_uint(mesg, &listsize);
5599280c577SChuck Lever if (err)
5609280c577SChuck Lever return err;
5619280c577SChuck Lever if (listsize > NFSEXP_XPRTSEC_NUM)
5629280c577SChuck Lever return -EINVAL;
5639280c577SChuck Lever
5649280c577SChuck Lever exp->ex_xprtsec_modes = 0;
5659280c577SChuck Lever for (i = 0; i < listsize; i++) {
5669280c577SChuck Lever err = get_uint(mesg, &mode);
5679280c577SChuck Lever if (err)
5689280c577SChuck Lever return err;
5699280c577SChuck Lever if (mode > NFSEXP_XPRTSEC_MTLS)
5709280c577SChuck Lever return -EINVAL;
5719280c577SChuck Lever exp->ex_xprtsec_modes |= mode;
5729280c577SChuck Lever }
5739280c577SChuck Lever return 0;
5749280c577SChuck Lever }
5759280c577SChuck Lever
5760d63790cSKinglong Mee static inline int
nfsd_uuid_parse(char ** mesg,char * buf,unsigned char ** puuid)57712ce5f8cSChristoph Hellwig nfsd_uuid_parse(char **mesg, char *buf, unsigned char **puuid)
5780d63790cSKinglong Mee {
5790d63790cSKinglong Mee int len;
5800d63790cSKinglong Mee
581be69da80SKinglong Mee /* more than one uuid */
582be69da80SKinglong Mee if (*puuid)
583be69da80SKinglong Mee return -EINVAL;
584be69da80SKinglong Mee
5850d63790cSKinglong Mee /* expect a 16 byte uuid encoded as \xXXXX... */
5860d63790cSKinglong Mee len = qword_get(mesg, buf, PAGE_SIZE);
58794eb3689SKinglong Mee if (len != EX_UUID_LEN)
5880d63790cSKinglong Mee return -EINVAL;
5890d63790cSKinglong Mee
59094eb3689SKinglong Mee *puuid = kmemdup(buf, EX_UUID_LEN, GFP_KERNEL);
5910d63790cSKinglong Mee if (*puuid == NULL)
5920d63790cSKinglong Mee return -ENOMEM;
5930d63790cSKinglong Mee
5940d63790cSKinglong Mee return 0;
5950d63790cSKinglong Mee }
5960d63790cSKinglong Mee
svc_export_parse(struct cache_detail * cd,char * mesg,int mlen)5971da177e4SLinus Torvalds static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
5981da177e4SLinus Torvalds {
5991da177e4SLinus Torvalds /* client path expiry [flags anonuid anongid fsid] */
6001da177e4SLinus Torvalds char *buf;
6011da177e4SLinus Torvalds int err;
6021da177e4SLinus Torvalds struct auth_domain *dom = NULL;
603c1a2a475SAl Viro struct svc_export exp = {}, *expp;
6041da177e4SLinus Torvalds int an_int;
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds if (mesg[mlen-1] != '\n')
6071da177e4SLinus Torvalds return -EINVAL;
6081da177e4SLinus Torvalds mesg[mlen-1] = 0;
6091da177e4SLinus Torvalds
6101da177e4SLinus Torvalds buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
611c1a2a475SAl Viro if (!buf)
612c1a2a475SAl Viro return -ENOMEM;
6131da177e4SLinus Torvalds
6141da177e4SLinus Torvalds /* client */
6151da177e4SLinus Torvalds err = -EINVAL;
61675bfb704SColin Ian King if (qword_get(&mesg, buf, PAGE_SIZE) <= 0)
617c1a2a475SAl Viro goto out;
6181da177e4SLinus Torvalds
6191da177e4SLinus Torvalds err = -ENOENT;
6201da177e4SLinus Torvalds dom = auth_domain_find(buf);
6211da177e4SLinus Torvalds if (!dom)
6221da177e4SLinus Torvalds goto out;
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds /* path */
6251da177e4SLinus Torvalds err = -EINVAL;
62675bfb704SColin Ian King if (qword_get(&mesg, buf, PAGE_SIZE) <= 0)
627c1a2a475SAl Viro goto out1;
6281da177e4SLinus Torvalds
629c1a2a475SAl Viro err = kern_path(buf, 0, &exp.ex_path);
630c1a2a475SAl Viro if (err)
631c1a2a475SAl Viro goto out1;
632c1a2a475SAl Viro
6331da177e4SLinus Torvalds exp.ex_client = dom;
634db3a3532SStanislav Kinsbursky exp.cd = cd;
6359cf514ccSChristoph Hellwig exp.ex_devid_map = NULL;
6369280c577SChuck Lever exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL;
637c1a2a475SAl Viro
6381da177e4SLinus Torvalds /* expiry */
639cf64b9bcSNeilBrown err = get_expiry(&mesg, &exp.h.expiry_time);
640cf64b9bcSNeilBrown if (err)
641c1a2a475SAl Viro goto out3;
6421da177e4SLinus Torvalds
6431da177e4SLinus Torvalds /* flags */
6441da177e4SLinus Torvalds err = get_int(&mesg, &an_int);
6454a4b8831SJ. Bruce Fields if (err == -ENOENT) {
6464a4b8831SJ. Bruce Fields err = 0;
6471da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &exp.h.flags);
6484a4b8831SJ. Bruce Fields } else {
649c1a2a475SAl Viro if (err || an_int < 0)
650c1a2a475SAl Viro goto out3;
6511da177e4SLinus Torvalds exp.ex_flags= an_int;
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds /* anon uid */
6541da177e4SLinus Torvalds err = get_int(&mesg, &an_int);
655c1a2a475SAl Viro if (err)
656c1a2a475SAl Viro goto out3;
657e45d1a18STrond Myklebust exp.ex_anon_uid= make_kuid(current_user_ns(), an_int);
6581da177e4SLinus Torvalds
6591da177e4SLinus Torvalds /* anon gid */
6601da177e4SLinus Torvalds err = get_int(&mesg, &an_int);
661c1a2a475SAl Viro if (err)
662c1a2a475SAl Viro goto out3;
663e45d1a18STrond Myklebust exp.ex_anon_gid= make_kgid(current_user_ns(), an_int);
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds /* fsid */
6661da177e4SLinus Torvalds err = get_int(&mesg, &an_int);
667c1a2a475SAl Viro if (err)
668c1a2a475SAl Viro goto out3;
6691da177e4SLinus Torvalds exp.ex_fsid = an_int;
6701da177e4SLinus Torvalds
67175bfb704SColin Ian King while (qword_get(&mesg, buf, PAGE_SIZE) > 0) {
672af6a4e28SNeilBrown if (strcmp(buf, "fsloc") == 0)
67393346919SManoj Naik err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
6740d63790cSKinglong Mee else if (strcmp(buf, "uuid") == 0)
67512ce5f8cSChristoph Hellwig err = nfsd_uuid_parse(&mesg, buf, &exp.ex_uuid);
6760d63790cSKinglong Mee else if (strcmp(buf, "secinfo") == 0)
677e677bfe4SAndy Adamson err = secinfo_parse(&mesg, buf, &exp);
6789280c577SChuck Lever else if (strcmp(buf, "xprtsec") == 0)
6799280c577SChuck Lever err = xprtsec_parse(&mesg, buf, &exp);
680e677bfe4SAndy Adamson else
681af6a4e28SNeilBrown /* quietly ignore unknown words and anything
682af6a4e28SNeilBrown * following. Newer user-space can try to set
683af6a4e28SNeilBrown * new values, then see what the result was.
684af6a4e28SNeilBrown */
685af6a4e28SNeilBrown break;
68693346919SManoj Naik if (err)
687c1a2a475SAl Viro goto out4;
6881da177e4SLinus Torvalds }
6891da177e4SLinus Torvalds
690899bf2ceSChristian Brauner err = check_export(&exp.ex_path, &exp.ex_flags, exp.ex_uuid);
691c1a2a475SAl Viro if (err)
692c1a2a475SAl Viro goto out4;
6939280c577SChuck Lever
694427d6c66SJ. Bruce Fields /*
6956f6cc320SJ. Bruce Fields * No point caching this if it would immediately expire.
6966f6cc320SJ. Bruce Fields * Also, this protects exportfs's dummy export from the
6976f6cc320SJ. Bruce Fields * anon_uid/anon_gid checks:
6986f6cc320SJ. Bruce Fields */
6996f6cc320SJ. Bruce Fields if (exp.h.expiry_time < seconds_since_boot())
7006f6cc320SJ. Bruce Fields goto out4;
7016f6cc320SJ. Bruce Fields /*
702427d6c66SJ. Bruce Fields * For some reason exportfs has been passing down an
703427d6c66SJ. Bruce Fields * invalid (-1) uid & gid on the "dummy" export which it
704427d6c66SJ. Bruce Fields * uses to test export support. To make sure exportfs
705427d6c66SJ. Bruce Fields * sees errors from check_export we therefore need to
706427d6c66SJ. Bruce Fields * delay these checks till after check_export:
707427d6c66SJ. Bruce Fields */
7086f6cc320SJ. Bruce Fields err = -EINVAL;
709427d6c66SJ. Bruce Fields if (!uid_valid(exp.ex_anon_uid))
710427d6c66SJ. Bruce Fields goto out4;
711427d6c66SJ. Bruce Fields if (!gid_valid(exp.ex_anon_gid))
712427d6c66SJ. Bruce Fields goto out4;
7136f6cc320SJ. Bruce Fields err = 0;
7149cf514ccSChristoph Hellwig
7159cf514ccSChristoph Hellwig nfsd4_setup_layout_type(&exp);
716af6a4e28SNeilBrown }
717af6a4e28SNeilBrown
7184f7774c3SNeilBrown expp = svc_export_lookup(&exp);
7196a30e47fSTrond Myklebust if (!expp) {
7206a30e47fSTrond Myklebust err = -ENOMEM;
7216a30e47fSTrond Myklebust goto out4;
7226a30e47fSTrond Myklebust }
7234f7774c3SNeilBrown expp = svc_export_update(&exp, expp);
7246a30e47fSTrond Myklebust if (expp) {
7256a30e47fSTrond Myklebust trace_nfsd_export_update(expp);
7261da177e4SLinus Torvalds cache_flush();
7274f7774c3SNeilBrown exp_put(expp);
7286a30e47fSTrond Myklebust } else
7296a30e47fSTrond Myklebust err = -ENOMEM;
730c1a2a475SAl Viro out4:
731af6a4e28SNeilBrown nfsd4_fslocs_free(&exp.ex_fslocs);
732af6a4e28SNeilBrown kfree(exp.ex_uuid);
733c1a2a475SAl Viro out3:
734c1a2a475SAl Viro path_put(&exp.ex_path);
735c1a2a475SAl Viro out1:
7361da177e4SLinus Torvalds auth_domain_put(dom);
737c1a2a475SAl Viro out:
7381da177e4SLinus Torvalds kfree(buf);
7391da177e4SLinus Torvalds return err;
7401da177e4SLinus Torvalds }
7411da177e4SLinus Torvalds
74293346919SManoj Naik static void exp_flags(struct seq_file *m, int flag, int fsid,
7434c1e1b34SEric W. Biederman kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);
74491fe39d3SJ. Bruce Fields static void show_secinfo(struct seq_file *m, struct svc_export *exp);
7451da177e4SLinus Torvalds
is_export_stats_file(struct seq_file * m)74620ad856eSAmir Goldstein static int is_export_stats_file(struct seq_file *m)
74720ad856eSAmir Goldstein {
74820ad856eSAmir Goldstein /*
74920ad856eSAmir Goldstein * The export_stats file uses the same ops as the exports file.
75020ad856eSAmir Goldstein * We use the file's name to determine the reported info per export.
75120ad856eSAmir Goldstein * There is no rename in nsfdfs, so d_name.name is stable.
75220ad856eSAmir Goldstein */
75320ad856eSAmir Goldstein return !strcmp(m->file->f_path.dentry->d_name.name, "export_stats");
75420ad856eSAmir Goldstein }
75520ad856eSAmir Goldstein
svc_export_show(struct seq_file * m,struct cache_detail * cd,struct cache_head * h)7561da177e4SLinus Torvalds static int svc_export_show(struct seq_file *m,
7571da177e4SLinus Torvalds struct cache_detail *cd,
7581da177e4SLinus Torvalds struct cache_head *h)
7591da177e4SLinus Torvalds {
7601da177e4SLinus Torvalds struct svc_export *exp;
76120ad856eSAmir Goldstein bool export_stats = is_export_stats_file(m);
7621da177e4SLinus Torvalds
7631da177e4SLinus Torvalds if (h == NULL) {
76420ad856eSAmir Goldstein if (export_stats)
76520ad856eSAmir Goldstein seq_puts(m, "#path domain start-time\n#\tstats\n");
76620ad856eSAmir Goldstein else
7671da177e4SLinus Torvalds seq_puts(m, "#path domain(flags)\n");
7681da177e4SLinus Torvalds return 0;
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds exp = container_of(h, struct svc_export, h);
771c32c2f63SJan Blunck seq_path(m, &exp->ex_path, " \t\n\\");
7721da177e4SLinus Torvalds seq_putc(m, '\t');
7731da177e4SLinus Torvalds seq_escape(m, exp->ex_client->name, " \t\n\\");
77420ad856eSAmir Goldstein if (export_stats) {
7759b31d561SChuck Lever struct percpu_counter *counter = exp->ex_stats->counter;
7769b31d561SChuck Lever
7779b31d561SChuck Lever seq_printf(m, "\t%lld\n", exp->ex_stats->start_time);
77820ad856eSAmir Goldstein seq_printf(m, "\tfh_stale: %lld\n",
7799b31d561SChuck Lever percpu_counter_sum_positive(&counter[EXP_STATS_FH_STALE]));
78020ad856eSAmir Goldstein seq_printf(m, "\tio_read: %lld\n",
7819b31d561SChuck Lever percpu_counter_sum_positive(&counter[EXP_STATS_IO_READ]));
78220ad856eSAmir Goldstein seq_printf(m, "\tio_write: %lld\n",
7839b31d561SChuck Lever percpu_counter_sum_positive(&counter[EXP_STATS_IO_WRITE]));
78420ad856eSAmir Goldstein seq_putc(m, '\n');
78520ad856eSAmir Goldstein return 0;
78620ad856eSAmir Goldstein }
7871da177e4SLinus Torvalds seq_putc(m, '(');
7881da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags) &&
789af6a4e28SNeilBrown !test_bit(CACHE_NEGATIVE, &h->flags)) {
7901da177e4SLinus Torvalds exp_flags(m, exp->ex_flags, exp->ex_fsid,
79193346919SManoj Naik exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
792af6a4e28SNeilBrown if (exp->ex_uuid) {
793af6a4e28SNeilBrown int i;
794af6a4e28SNeilBrown seq_puts(m, ",uuid=");
79594eb3689SKinglong Mee for (i = 0; i < EX_UUID_LEN; i++) {
796af6a4e28SNeilBrown if ((i&3) == 0 && i)
797af6a4e28SNeilBrown seq_putc(m, ':');
798af6a4e28SNeilBrown seq_printf(m, "%02x", exp->ex_uuid[i]);
799af6a4e28SNeilBrown }
800af6a4e28SNeilBrown }
80191fe39d3SJ. Bruce Fields show_secinfo(m, exp);
802af6a4e28SNeilBrown }
8031da177e4SLinus Torvalds seq_puts(m, ")\n");
8041da177e4SLinus Torvalds return 0;
8051da177e4SLinus Torvalds }
svc_export_match(struct cache_head * a,struct cache_head * b)8064f7774c3SNeilBrown static int svc_export_match(struct cache_head *a, struct cache_head *b)
8074f7774c3SNeilBrown {
8084f7774c3SNeilBrown struct svc_export *orig = container_of(a, struct svc_export, h);
8094f7774c3SNeilBrown struct svc_export *new = container_of(b, struct svc_export, h);
8104f7774c3SNeilBrown return orig->ex_client == new->ex_client &&
811b77a4b2eSKinglong Mee path_equal(&orig->ex_path, &new->ex_path);
8124f7774c3SNeilBrown }
8134f7774c3SNeilBrown
svc_export_init(struct cache_head * cnew,struct cache_head * citem)8144f7774c3SNeilBrown static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
8154f7774c3SNeilBrown {
8164f7774c3SNeilBrown struct svc_export *new = container_of(cnew, struct svc_export, h);
8174f7774c3SNeilBrown struct svc_export *item = container_of(citem, struct svc_export, h);
8184f7774c3SNeilBrown
8194f7774c3SNeilBrown kref_get(&item->ex_client->ref);
8204f7774c3SNeilBrown new->ex_client = item->ex_client;
8210da22a91SKinglong Mee new->ex_path = item->ex_path;
8220da22a91SKinglong Mee path_get(&item->ex_path);
82393346919SManoj Naik new->ex_fslocs.locations = NULL;
82493346919SManoj Naik new->ex_fslocs.locations_count = 0;
82593346919SManoj Naik new->ex_fslocs.migrated = 0;
8268a4c3926SJeff Layton new->ex_layout_types = 0;
8272eeb9b2aSJeff Layton new->ex_uuid = NULL;
828db3a3532SStanislav Kinsbursky new->cd = item->cd;
8299b31d561SChuck Lever export_stats_reset(new->ex_stats);
8304f7774c3SNeilBrown }
8314f7774c3SNeilBrown
export_update(struct cache_head * cnew,struct cache_head * citem)8324f7774c3SNeilBrown static void export_update(struct cache_head *cnew, struct cache_head *citem)
8334f7774c3SNeilBrown {
8344f7774c3SNeilBrown struct svc_export *new = container_of(cnew, struct svc_export, h);
8354f7774c3SNeilBrown struct svc_export *item = container_of(citem, struct svc_export, h);
836e677bfe4SAndy Adamson int i;
8374f7774c3SNeilBrown
8384f7774c3SNeilBrown new->ex_flags = item->ex_flags;
8394f7774c3SNeilBrown new->ex_anon_uid = item->ex_anon_uid;
8404f7774c3SNeilBrown new->ex_anon_gid = item->ex_anon_gid;
8414f7774c3SNeilBrown new->ex_fsid = item->ex_fsid;
8429cf514ccSChristoph Hellwig new->ex_devid_map = item->ex_devid_map;
8439cf514ccSChristoph Hellwig item->ex_devid_map = NULL;
844af6a4e28SNeilBrown new->ex_uuid = item->ex_uuid;
845af6a4e28SNeilBrown item->ex_uuid = NULL;
84693346919SManoj Naik new->ex_fslocs.locations = item->ex_fslocs.locations;
84793346919SManoj Naik item->ex_fslocs.locations = NULL;
84893346919SManoj Naik new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
84993346919SManoj Naik item->ex_fslocs.locations_count = 0;
85093346919SManoj Naik new->ex_fslocs.migrated = item->ex_fslocs.migrated;
85193346919SManoj Naik item->ex_fslocs.migrated = 0;
8528a4c3926SJeff Layton new->ex_layout_types = item->ex_layout_types;
853e677bfe4SAndy Adamson new->ex_nflavors = item->ex_nflavors;
854e677bfe4SAndy Adamson for (i = 0; i < MAX_SECINFO_LIST; i++) {
855e677bfe4SAndy Adamson new->ex_flavors[i] = item->ex_flavors[i];
856e677bfe4SAndy Adamson }
8579280c577SChuck Lever new->ex_xprtsec_modes = item->ex_xprtsec_modes;
8584f7774c3SNeilBrown }
8594f7774c3SNeilBrown
svc_export_alloc(void)8604f7774c3SNeilBrown static struct cache_head *svc_export_alloc(void)
8614f7774c3SNeilBrown {
8624f7774c3SNeilBrown struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
86320ad856eSAmir Goldstein if (!i)
8644f7774c3SNeilBrown return NULL;
86520ad856eSAmir Goldstein
8669b31d561SChuck Lever i->ex_stats = kmalloc(sizeof(*(i->ex_stats)), GFP_KERNEL);
8679b31d561SChuck Lever if (!i->ex_stats) {
8689b31d561SChuck Lever kfree(i);
8699b31d561SChuck Lever return NULL;
8709b31d561SChuck Lever }
8719b31d561SChuck Lever
8729b31d561SChuck Lever if (export_stats_init(i->ex_stats)) {
8739b31d561SChuck Lever kfree(i->ex_stats);
87420ad856eSAmir Goldstein kfree(i);
87520ad856eSAmir Goldstein return NULL;
87620ad856eSAmir Goldstein }
87720ad856eSAmir Goldstein
87820ad856eSAmir Goldstein return &i->h;
8794f7774c3SNeilBrown }
8804f7774c3SNeilBrown
881ae2e408eSBhumika Goyal static const struct cache_detail svc_export_cache_template = {
882f35279d3SBruce Allan .owner = THIS_MODULE,
8831da177e4SLinus Torvalds .hash_size = EXPORT_HASHMAX,
8841da177e4SLinus Torvalds .name = "nfsd.export",
8851da177e4SLinus Torvalds .cache_put = svc_export_put,
88665286b88STrond Myklebust .cache_upcall = svc_export_upcall,
88773fb847aSStanislav Kinsbursky .cache_request = svc_export_request,
8881da177e4SLinus Torvalds .cache_parse = svc_export_parse,
8891da177e4SLinus Torvalds .cache_show = svc_export_show,
8904f7774c3SNeilBrown .match = svc_export_match,
8914f7774c3SNeilBrown .init = svc_export_init,
8924f7774c3SNeilBrown .update = export_update,
8934f7774c3SNeilBrown .alloc = svc_export_alloc,
8941da177e4SLinus Torvalds };
8951da177e4SLinus Torvalds
89661f8603dSNeilBrown static int
svc_export_hash(struct svc_export * exp)89761f8603dSNeilBrown svc_export_hash(struct svc_export *exp)
89861f8603dSNeilBrown {
89961f8603dSNeilBrown int hash;
90061f8603dSNeilBrown
90161f8603dSNeilBrown hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
90261f8603dSNeilBrown hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
90361f8603dSNeilBrown hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
90461f8603dSNeilBrown return hash;
90561f8603dSNeilBrown }
90661f8603dSNeilBrown
9074f7774c3SNeilBrown static struct svc_export *
svc_export_lookup(struct svc_export * exp)9084f7774c3SNeilBrown svc_export_lookup(struct svc_export *exp)
9091da177e4SLinus Torvalds {
9104f7774c3SNeilBrown struct cache_head *ch;
91161f8603dSNeilBrown int hash = svc_export_hash(exp);
9124f7774c3SNeilBrown
9139ceddd9dSTrond Myklebust ch = sunrpc_cache_lookup_rcu(exp->cd, &exp->h, hash);
9144f7774c3SNeilBrown if (ch)
9154f7774c3SNeilBrown return container_of(ch, struct svc_export, h);
9164f7774c3SNeilBrown else
9174f7774c3SNeilBrown return NULL;
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds
92074cae61aSAdrian Bunk static struct svc_export *
svc_export_update(struct svc_export * new,struct svc_export * old)9214f7774c3SNeilBrown svc_export_update(struct svc_export *new, struct svc_export *old)
9221da177e4SLinus Torvalds {
9234f7774c3SNeilBrown struct cache_head *ch;
92461f8603dSNeilBrown int hash = svc_export_hash(old);
9251da177e4SLinus Torvalds
926db3a3532SStanislav Kinsbursky ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash);
9274f7774c3SNeilBrown if (ch)
9284f7774c3SNeilBrown return container_of(ch, struct svc_export, h);
9294f7774c3SNeilBrown else
9304f7774c3SNeilBrown return NULL;
9314f7774c3SNeilBrown }
9321da177e4SLinus Torvalds
9331da177e4SLinus Torvalds
93474cae61aSAdrian Bunk static struct svc_expkey *
exp_find_key(struct cache_detail * cd,struct auth_domain * clp,int fsid_type,u32 * fsidv,struct cache_req * reqp)935e6d615f7SKinglong Mee exp_find_key(struct cache_detail *cd, struct auth_domain *clp, int fsid_type,
936c89172e3SStanislav Kinsbursky u32 *fsidv, struct cache_req *reqp)
9371da177e4SLinus Torvalds {
9381da177e4SLinus Torvalds struct svc_expkey key, *ek;
9391da177e4SLinus Torvalds int err;
9401da177e4SLinus Torvalds
9411da177e4SLinus Torvalds if (!clp)
9422d3bb252SJ. Bruce Fields return ERR_PTR(-ENOENT);
9431da177e4SLinus Torvalds
9441da177e4SLinus Torvalds key.ek_client = clp;
9451da177e4SLinus Torvalds key.ek_fsidtype = fsid_type;
9461da177e4SLinus Torvalds memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
9471da177e4SLinus Torvalds
948c89172e3SStanislav Kinsbursky ek = svc_expkey_lookup(cd, &key);
9492d3bb252SJ. Bruce Fields if (ek == NULL)
9502d3bb252SJ. Bruce Fields return ERR_PTR(-ENOMEM);
951c89172e3SStanislav Kinsbursky err = cache_check(cd, &ek->h, reqp);
952cf749f3cSTrond Myklebust if (err) {
953cf749f3cSTrond Myklebust trace_nfsd_exp_find_key(&key, err);
9542d3bb252SJ. Bruce Fields return ERR_PTR(err);
955cf749f3cSTrond Myklebust }
9561da177e4SLinus Torvalds return ek;
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds
959e6d615f7SKinglong Mee static struct svc_export *
exp_get_by_name(struct cache_detail * cd,struct auth_domain * clp,const struct path * path,struct cache_req * reqp)960e6d615f7SKinglong Mee exp_get_by_name(struct cache_detail *cd, struct auth_domain *clp,
9612a75cfa6SStanislav Kinsbursky const struct path *path, struct cache_req *reqp)
9621da177e4SLinus Torvalds {
9631da177e4SLinus Torvalds struct svc_export *exp, key;
9642d3bb252SJ. Bruce Fields int err;
9651da177e4SLinus Torvalds
9661da177e4SLinus Torvalds if (!clp)
9672d3bb252SJ. Bruce Fields return ERR_PTR(-ENOENT);
9681da177e4SLinus Torvalds
9691da177e4SLinus Torvalds key.ex_client = clp;
97055430e2eSAl Viro key.ex_path = *path;
9712a75cfa6SStanislav Kinsbursky key.cd = cd;
9721da177e4SLinus Torvalds
9734f7774c3SNeilBrown exp = svc_export_lookup(&key);
9742d3bb252SJ. Bruce Fields if (exp == NULL)
9752d3bb252SJ. Bruce Fields return ERR_PTR(-ENOMEM);
9762a75cfa6SStanislav Kinsbursky err = cache_check(cd, &exp->h, reqp);
977cf749f3cSTrond Myklebust if (err) {
978cf749f3cSTrond Myklebust trace_nfsd_exp_get_by_name(&key, err);
9792d3bb252SJ. Bruce Fields return ERR_PTR(err);
980cf749f3cSTrond Myklebust }
9811da177e4SLinus Torvalds return exp;
9821da177e4SLinus Torvalds }
9831da177e4SLinus Torvalds
9841da177e4SLinus Torvalds /*
9851da177e4SLinus Torvalds * Find the export entry for a given dentry.
9861da177e4SLinus Torvalds */
987e6d615f7SKinglong Mee static struct svc_export *
exp_parent(struct cache_detail * cd,struct auth_domain * clp,struct path * path)988e6d615f7SKinglong Mee exp_parent(struct cache_detail *cd, struct auth_domain *clp, struct path *path)
9891da177e4SLinus Torvalds {
9905bf3bd2bSAl Viro struct dentry *saved = dget(path->dentry);
991e6d615f7SKinglong Mee struct svc_export *exp = exp_get_by_name(cd, clp, path, NULL);
9921da177e4SLinus Torvalds
9935bf3bd2bSAl Viro while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
9945bf3bd2bSAl Viro struct dentry *parent = dget_parent(path->dentry);
9955bf3bd2bSAl Viro dput(path->dentry);
9965bf3bd2bSAl Viro path->dentry = parent;
9972a75cfa6SStanislav Kinsbursky exp = exp_get_by_name(cd, clp, path, NULL);
9981da177e4SLinus Torvalds }
9995bf3bd2bSAl Viro dput(path->dentry);
10005bf3bd2bSAl Viro path->dentry = saved;
10011da177e4SLinus Torvalds return exp;
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds
10041da177e4SLinus Torvalds
10051da177e4SLinus Torvalds
10061da177e4SLinus Torvalds /*
10071da177e4SLinus Torvalds * Obtain the root fh on behalf of a client.
10081da177e4SLinus Torvalds * This could be done in user space, but I feel that it adds some safety
10091da177e4SLinus Torvalds * since its harder to fool a kernel module than a user space program.
10101da177e4SLinus Torvalds */
10111da177e4SLinus Torvalds int
exp_rootfh(struct net * net,struct auth_domain * clp,char * name,struct knfsd_fh * f,int maxsize)1012e6d615f7SKinglong Mee exp_rootfh(struct net *net, struct auth_domain *clp, char *name,
10132a75cfa6SStanislav Kinsbursky struct knfsd_fh *f, int maxsize)
10141da177e4SLinus Torvalds {
10151da177e4SLinus Torvalds struct svc_export *exp;
1016a63bb996SAl Viro struct path path;
10171da177e4SLinus Torvalds struct inode *inode;
10181da177e4SLinus Torvalds struct svc_fh fh;
10191da177e4SLinus Torvalds int err;
1020b3853e0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1021b3853e0eSStanislav Kinsbursky struct cache_detail *cd = nn->svc_export_cache;
10221da177e4SLinus Torvalds
10231da177e4SLinus Torvalds err = -EPERM;
10241da177e4SLinus Torvalds /* NB: we probably ought to check that it's NUL-terminated */
1025a63bb996SAl Viro if (kern_path(name, 0, &path)) {
1026a63bb996SAl Viro printk("nfsd: exp_rootfh path not found %s", name);
10271da177e4SLinus Torvalds return err;
10281da177e4SLinus Torvalds }
10292b0143b5SDavid Howells inode = d_inode(path.dentry);
10301da177e4SLinus Torvalds
10311da177e4SLinus Torvalds dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
1032a63bb996SAl Viro name, path.dentry, clp->name,
10331da177e4SLinus Torvalds inode->i_sb->s_id, inode->i_ino);
10342a75cfa6SStanislav Kinsbursky exp = exp_parent(cd, clp, &path);
10354b41bd85SJ.Bruce Fields if (IS_ERR(exp)) {
10364b41bd85SJ.Bruce Fields err = PTR_ERR(exp);
10374b41bd85SJ.Bruce Fields goto out;
10384b41bd85SJ.Bruce Fields }
10391da177e4SLinus Torvalds
10401da177e4SLinus Torvalds /*
10411da177e4SLinus Torvalds * fh must be initialized before calling fh_compose
10421da177e4SLinus Torvalds */
10431da177e4SLinus Torvalds fh_init(&fh, maxsize);
1044a63bb996SAl Viro if (fh_compose(&fh, exp, path.dentry, NULL))
10451da177e4SLinus Torvalds err = -EINVAL;
10461da177e4SLinus Torvalds else
10471da177e4SLinus Torvalds err = 0;
10481da177e4SLinus Torvalds memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
10491da177e4SLinus Torvalds fh_put(&fh);
10501da177e4SLinus Torvalds exp_put(exp);
10511da177e4SLinus Torvalds out:
1052a63bb996SAl Viro path_put(&path);
10531da177e4SLinus Torvalds return err;
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds
exp_find(struct cache_detail * cd,struct auth_domain * clp,int fsid_type,u32 * fsidv,struct cache_req * reqp)10562a75cfa6SStanislav Kinsbursky static struct svc_export *exp_find(struct cache_detail *cd,
10572a75cfa6SStanislav Kinsbursky struct auth_domain *clp, int fsid_type,
1058cce76f9bSAdrian Bunk u32 *fsidv, struct cache_req *reqp)
1059eab7e2e6SNeilBrown {
1060eab7e2e6SNeilBrown struct svc_export *exp;
1061e5f06f72SStanislav Kinsbursky struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id);
1062e5f06f72SStanislav Kinsbursky struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp);
10632d3bb252SJ. Bruce Fields if (IS_ERR(ek))
1064e231c2eeSDavid Howells return ERR_CAST(ek);
1065eab7e2e6SNeilBrown
10662a75cfa6SStanislav Kinsbursky exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp);
1067e5f06f72SStanislav Kinsbursky cache_put(&ek->h, nn->svc_expkey_cache);
1068eab7e2e6SNeilBrown
10692d3bb252SJ. Bruce Fields if (IS_ERR(exp))
1070e231c2eeSDavid Howells return ERR_CAST(exp);
1071eab7e2e6SNeilBrown return exp;
1072eab7e2e6SNeilBrown }
1073eab7e2e6SNeilBrown
check_nfsd_access(struct svc_export * exp,struct svc_rqst * rqstp)107432c1eb0cSAndy Adamson __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
107532c1eb0cSAndy Adamson {
10769280c577SChuck Lever struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
10779280c577SChuck Lever struct svc_xprt *xprt = rqstp->rq_xprt;
107832c1eb0cSAndy Adamson
10799280c577SChuck Lever if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) {
10809280c577SChuck Lever if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags))
10819280c577SChuck Lever goto ok;
10829280c577SChuck Lever }
10839280c577SChuck Lever if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) {
10849280c577SChuck Lever if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
10859280c577SChuck Lever !test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
10869280c577SChuck Lever goto ok;
10879280c577SChuck Lever }
10889280c577SChuck Lever if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) {
10899280c577SChuck Lever if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
10909280c577SChuck Lever test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
10919280c577SChuck Lever goto ok;
10929280c577SChuck Lever }
10939280c577SChuck Lever goto denied;
10949280c577SChuck Lever
10959280c577SChuck Lever ok:
109632c1eb0cSAndy Adamson /* legacy gss-only clients are always OK: */
109732c1eb0cSAndy Adamson if (exp->ex_client == rqstp->rq_gssclient)
109832c1eb0cSAndy Adamson return 0;
109932c1eb0cSAndy Adamson /* ip-address based client; check sec= export option: */
110032c1eb0cSAndy Adamson for (f = exp->ex_flavors; f < end; f++) {
1101d5497fc6SJ. Bruce Fields if (f->pseudoflavor == rqstp->rq_cred.cr_flavor)
110232c1eb0cSAndy Adamson return 0;
110332c1eb0cSAndy Adamson }
110432c1eb0cSAndy Adamson /* defaults in absence of sec= options: */
110532c1eb0cSAndy Adamson if (exp->ex_nflavors == 0) {
1106d5497fc6SJ. Bruce Fields if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
1107d5497fc6SJ. Bruce Fields rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
110832c1eb0cSAndy Adamson return 0;
110932c1eb0cSAndy Adamson }
1110ed941643SAndrew Elble
1111ed941643SAndrew Elble /* If the compound op contains a spo_must_allowed op,
1112ed941643SAndrew Elble * it will be sent with integrity/protection which
1113ed941643SAndrew Elble * will have to be expressly allowed on mounts that
1114ed941643SAndrew Elble * don't support it
1115ed941643SAndrew Elble */
1116ed941643SAndrew Elble
1117ed941643SAndrew Elble if (nfsd4_spo_must_allow(rqstp))
1118ed941643SAndrew Elble return 0;
1119ed941643SAndrew Elble
11209280c577SChuck Lever denied:
11214b74fd79SChuck Lever return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
112232c1eb0cSAndy Adamson }
112332c1eb0cSAndy Adamson
11240989a788SJ. Bruce Fields /*
11252ea2209fSJ. Bruce Fields * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
11262ea2209fSJ. Bruce Fields * auth_unix client) if it's available and has secinfo information;
11272ea2209fSJ. Bruce Fields * otherwise, will try to use rq_gssclient.
11282ea2209fSJ. Bruce Fields *
11290989a788SJ. Bruce Fields * Called from functions that handle requests; functions that do work on
11300989a788SJ. Bruce Fields * behalf of mountd are passed a single client name to use, and should
11310989a788SJ. Bruce Fields * use exp_get_by_name() or exp_find().
11320989a788SJ. Bruce Fields */
11330989a788SJ. Bruce Fields struct svc_export *
rqst_exp_get_by_name(struct svc_rqst * rqstp,struct path * path)113491c9fa8fSAl Viro rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
11350989a788SJ. Bruce Fields {
11369a25b96cSJ. Bruce Fields struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
11379695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1138b3853e0eSStanislav Kinsbursky struct cache_detail *cd = nn->svc_export_cache;
11393ab4d8b1SJ. Bruce Fields
11402ea2209fSJ. Bruce Fields if (rqstp->rq_client == NULL)
11412ea2209fSJ. Bruce Fields goto gss;
11422ea2209fSJ. Bruce Fields
11432ea2209fSJ. Bruce Fields /* First try the auth_unix client: */
11442a75cfa6SStanislav Kinsbursky exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle);
11452ea2209fSJ. Bruce Fields if (PTR_ERR(exp) == -ENOENT)
11462ea2209fSJ. Bruce Fields goto gss;
11472ea2209fSJ. Bruce Fields if (IS_ERR(exp))
11482ea2209fSJ. Bruce Fields return exp;
11492ea2209fSJ. Bruce Fields /* If it has secinfo, assume there are no gss/... clients */
11502ea2209fSJ. Bruce Fields if (exp->ex_nflavors > 0)
11512ea2209fSJ. Bruce Fields return exp;
11522ea2209fSJ. Bruce Fields gss:
11532ea2209fSJ. Bruce Fields /* Otherwise, try falling back on gss client */
11542ea2209fSJ. Bruce Fields if (rqstp->rq_gssclient == NULL)
11552ea2209fSJ. Bruce Fields return exp;
11562a75cfa6SStanislav Kinsbursky gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle);
11572ea2209fSJ. Bruce Fields if (PTR_ERR(gssexp) == -ENOENT)
11582ea2209fSJ. Bruce Fields return exp;
11599a25b96cSJ. Bruce Fields if (!IS_ERR(exp))
11602ea2209fSJ. Bruce Fields exp_put(exp);
11612ea2209fSJ. Bruce Fields return gssexp;
11620989a788SJ. Bruce Fields }
11630989a788SJ. Bruce Fields
11640989a788SJ. Bruce Fields struct svc_export *
rqst_exp_find(struct svc_rqst * rqstp,int fsid_type,u32 * fsidv)11650989a788SJ. Bruce Fields rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
11660989a788SJ. Bruce Fields {
11679a25b96cSJ. Bruce Fields struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
11689695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1169b3853e0eSStanislav Kinsbursky struct cache_detail *cd = nn->svc_export_cache;
11703ab4d8b1SJ. Bruce Fields
11712ea2209fSJ. Bruce Fields if (rqstp->rq_client == NULL)
11722ea2209fSJ. Bruce Fields goto gss;
11732ea2209fSJ. Bruce Fields
11742ea2209fSJ. Bruce Fields /* First try the auth_unix client: */
11752a75cfa6SStanislav Kinsbursky exp = exp_find(cd, rqstp->rq_client, fsid_type,
11762a75cfa6SStanislav Kinsbursky fsidv, &rqstp->rq_chandle);
11772ea2209fSJ. Bruce Fields if (PTR_ERR(exp) == -ENOENT)
11782ea2209fSJ. Bruce Fields goto gss;
11792ea2209fSJ. Bruce Fields if (IS_ERR(exp))
11802ea2209fSJ. Bruce Fields return exp;
11812ea2209fSJ. Bruce Fields /* If it has secinfo, assume there are no gss/... clients */
11822ea2209fSJ. Bruce Fields if (exp->ex_nflavors > 0)
11832ea2209fSJ. Bruce Fields return exp;
11842ea2209fSJ. Bruce Fields gss:
11852ea2209fSJ. Bruce Fields /* Otherwise, try falling back on gss client */
11862ea2209fSJ. Bruce Fields if (rqstp->rq_gssclient == NULL)
11872ea2209fSJ. Bruce Fields return exp;
11882a75cfa6SStanislav Kinsbursky gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv,
11892ea2209fSJ. Bruce Fields &rqstp->rq_chandle);
11902ea2209fSJ. Bruce Fields if (PTR_ERR(gssexp) == -ENOENT)
11912ea2209fSJ. Bruce Fields return exp;
11929a25b96cSJ. Bruce Fields if (!IS_ERR(exp))
11932ea2209fSJ. Bruce Fields exp_put(exp);
11942ea2209fSJ. Bruce Fields return gssexp;
11950989a788SJ. Bruce Fields }
11960989a788SJ. Bruce Fields
11970989a788SJ. Bruce Fields struct svc_export *
rqst_exp_parent(struct svc_rqst * rqstp,struct path * path)1198e64c390cSAl Viro rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
11990989a788SJ. Bruce Fields {
1200e64c390cSAl Viro struct dentry *saved = dget(path->dentry);
1201e64c390cSAl Viro struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
12023ab4d8b1SJ. Bruce Fields
1203e64c390cSAl Viro while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
1204e64c390cSAl Viro struct dentry *parent = dget_parent(path->dentry);
1205e64c390cSAl Viro dput(path->dentry);
1206e64c390cSAl Viro path->dentry = parent;
1207e64c390cSAl Viro exp = rqst_exp_get_by_name(rqstp, path);
12082ea2209fSJ. Bruce Fields }
1209e64c390cSAl Viro dput(path->dentry);
1210e64c390cSAl Viro path->dentry = saved;
12112ea2209fSJ. Bruce Fields return exp;
12120989a788SJ. Bruce Fields }
1213eab7e2e6SNeilBrown
rqst_find_fsidzero_export(struct svc_rqst * rqstp)1214ed748aacSTrond Myklebust struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
1215f39bde24SJ. Bruce Fields {
1216f39bde24SJ. Bruce Fields u32 fsidv[2];
1217f39bde24SJ. Bruce Fields
1218f39bde24SJ. Bruce Fields mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1219f39bde24SJ. Bruce Fields
1220260c64d2SJ. Bruce Fields return rqst_exp_find(rqstp, FSID_NUM, fsidv);
1221f39bde24SJ. Bruce Fields }
1222f39bde24SJ. Bruce Fields
12231da177e4SLinus Torvalds /*
12241da177e4SLinus Torvalds * Called when we need the filehandle for the root of the pseudofs,
12251da177e4SLinus Torvalds * for a given NFSv4 client. The root is defined to be the
12261da177e4SLinus Torvalds * export point with fsid==0
12271da177e4SLinus Torvalds */
1228c7afef1fSAl Viro __be32
exp_pseudoroot(struct svc_rqst * rqstp,struct svc_fh * fhp)1229df547efbSJ. Bruce Fields exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
12301da177e4SLinus Torvalds {
1231eab7e2e6SNeilBrown struct svc_export *exp;
1232c7afef1fSAl Viro __be32 rv;
12331da177e4SLinus Torvalds
1234ed748aacSTrond Myklebust exp = rqst_find_fsidzero_export(rqstp);
12356899320cSJ.Bruce Fields if (IS_ERR(exp))
12366899320cSJ.Bruce Fields return nfserrno(PTR_ERR(exp));
123754775491SJan Blunck rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
1238f2d39586SNeilBrown exp_put(exp);
12391da177e4SLinus Torvalds return rv;
12401da177e4SLinus Torvalds }
12411da177e4SLinus Torvalds
12421da177e4SLinus Torvalds static struct flags {
12431da177e4SLinus Torvalds int flag;
12441da177e4SLinus Torvalds char *name[2];
12451da177e4SLinus Torvalds } expflags[] = {
12461da177e4SLinus Torvalds { NFSEXP_READONLY, {"ro", "rw"}},
12471da177e4SLinus Torvalds { NFSEXP_INSECURE_PORT, {"insecure", ""}},
12481da177e4SLinus Torvalds { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
12491da177e4SLinus Torvalds { NFSEXP_ALLSQUASH, {"all_squash", ""}},
12501da177e4SLinus Torvalds { NFSEXP_ASYNC, {"async", "sync"}},
12511da177e4SLinus Torvalds { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
125218c01ab3SRajesh Ghanekar { NFSEXP_NOREADDIRPLUS, {"nordirplus", ""}},
12531da177e4SLinus Torvalds { NFSEXP_NOHIDE, {"nohide", ""}},
12541da177e4SLinus Torvalds { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
12551da177e4SLinus Torvalds { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
12561da177e4SLinus Torvalds { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1257eb4c86c6SSteve Dickson { NFSEXP_V4ROOT, {"v4root", ""}},
12589b3075c5SChristoph Hellwig { NFSEXP_PNFS, {"pnfs", ""}},
125932ddd944SJ. Bruce Fields { NFSEXP_SECURITY_LABEL, {"security_label", ""}},
12601da177e4SLinus Torvalds { 0, {"", ""}}
12611da177e4SLinus Torvalds };
12621da177e4SLinus Torvalds
show_expflags(struct seq_file * m,int flags,int mask)1263ac34cdb0SJ. Bruce Fields static void show_expflags(struct seq_file *m, int flags, int mask)
12641da177e4SLinus Torvalds {
12651da177e4SLinus Torvalds struct flags *flg;
1266ac34cdb0SJ. Bruce Fields int state, first = 0;
12671da177e4SLinus Torvalds
12681da177e4SLinus Torvalds for (flg = expflags; flg->flag; flg++) {
1269ac34cdb0SJ. Bruce Fields if (flg->flag & ~mask)
1270ac34cdb0SJ. Bruce Fields continue;
1271ac34cdb0SJ. Bruce Fields state = (flg->flag & flags) ? 0 : 1;
12721da177e4SLinus Torvalds if (*flg->name[state])
12731da177e4SLinus Torvalds seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
12741da177e4SLinus Torvalds }
1275ac34cdb0SJ. Bruce Fields }
1276ac34cdb0SJ. Bruce Fields
show_secinfo_flags(struct seq_file * m,int flags)127791fe39d3SJ. Bruce Fields static void show_secinfo_flags(struct seq_file *m, int flags)
127891fe39d3SJ. Bruce Fields {
127991fe39d3SJ. Bruce Fields seq_printf(m, ",");
128091fe39d3SJ. Bruce Fields show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
128191fe39d3SJ. Bruce Fields }
128291fe39d3SJ. Bruce Fields
secinfo_flags_equal(int f,int g)128374ec1e12SJ. Bruce Fields static bool secinfo_flags_equal(int f, int g)
128474ec1e12SJ. Bruce Fields {
128574ec1e12SJ. Bruce Fields f &= NFSEXP_SECINFO_FLAGS;
128674ec1e12SJ. Bruce Fields g &= NFSEXP_SECINFO_FLAGS;
128774ec1e12SJ. Bruce Fields return f == g;
128874ec1e12SJ. Bruce Fields }
128974ec1e12SJ. Bruce Fields
show_secinfo_run(struct seq_file * m,struct exp_flavor_info ** fp,struct exp_flavor_info * end)129074ec1e12SJ. Bruce Fields static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
129174ec1e12SJ. Bruce Fields {
129274ec1e12SJ. Bruce Fields int flags;
129374ec1e12SJ. Bruce Fields
129474ec1e12SJ. Bruce Fields flags = (*fp)->flags;
129574ec1e12SJ. Bruce Fields seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
129674ec1e12SJ. Bruce Fields (*fp)++;
129774ec1e12SJ. Bruce Fields while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
129874ec1e12SJ. Bruce Fields seq_printf(m, ":%d", (*fp)->pseudoflavor);
129974ec1e12SJ. Bruce Fields (*fp)++;
130074ec1e12SJ. Bruce Fields }
130174ec1e12SJ. Bruce Fields return flags;
130274ec1e12SJ. Bruce Fields }
130374ec1e12SJ. Bruce Fields
show_secinfo(struct seq_file * m,struct svc_export * exp)130491fe39d3SJ. Bruce Fields static void show_secinfo(struct seq_file *m, struct svc_export *exp)
130591fe39d3SJ. Bruce Fields {
130691fe39d3SJ. Bruce Fields struct exp_flavor_info *f;
130791fe39d3SJ. Bruce Fields struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
130874ec1e12SJ. Bruce Fields int flags;
130991fe39d3SJ. Bruce Fields
131091fe39d3SJ. Bruce Fields if (exp->ex_nflavors == 0)
131191fe39d3SJ. Bruce Fields return;
131274ec1e12SJ. Bruce Fields f = exp->ex_flavors;
131374ec1e12SJ. Bruce Fields flags = show_secinfo_run(m, &f, end);
131474ec1e12SJ. Bruce Fields if (!secinfo_flags_equal(flags, exp->ex_flags))
131574ec1e12SJ. Bruce Fields show_secinfo_flags(m, flags);
131674ec1e12SJ. Bruce Fields while (f != end) {
131774ec1e12SJ. Bruce Fields flags = show_secinfo_run(m, &f, end);
131874ec1e12SJ. Bruce Fields show_secinfo_flags(m, flags);
131991fe39d3SJ. Bruce Fields }
132091fe39d3SJ. Bruce Fields }
132191fe39d3SJ. Bruce Fields
exp_flags(struct seq_file * m,int flag,int fsid,kuid_t anonu,kgid_t anong,struct nfsd4_fs_locations * fsloc)1322ac34cdb0SJ. Bruce Fields static void exp_flags(struct seq_file *m, int flag, int fsid,
13234c1e1b34SEric W. Biederman kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
1324ac34cdb0SJ. Bruce Fields {
1325e45d1a18STrond Myklebust struct user_namespace *userns = m->file->f_cred->user_ns;
1326e45d1a18STrond Myklebust
1327ac34cdb0SJ. Bruce Fields show_expflags(m, flag, NFSEXP_ALLFLAGS);
13281da177e4SLinus Torvalds if (flag & NFSEXP_FSID)
1329ac34cdb0SJ. Bruce Fields seq_printf(m, ",fsid=%d", fsid);
1330e45d1a18STrond Myklebust if (!uid_eq(anonu, make_kuid(userns, (uid_t)-2)) &&
1331e45d1a18STrond Myklebust !uid_eq(anonu, make_kuid(userns, 0x10000-2)))
1332e45d1a18STrond Myklebust seq_printf(m, ",anonuid=%u", from_kuid_munged(userns, anonu));
1333e45d1a18STrond Myklebust if (!gid_eq(anong, make_kgid(userns, (gid_t)-2)) &&
1334e45d1a18STrond Myklebust !gid_eq(anong, make_kgid(userns, 0x10000-2)))
1335e45d1a18STrond Myklebust seq_printf(m, ",anongid=%u", from_kgid_munged(userns, anong));
133693346919SManoj Naik if (fsloc && fsloc->locations_count > 0) {
133793346919SManoj Naik char *loctype = (fsloc->migrated) ? "refer" : "replicas";
133893346919SManoj Naik int i;
133993346919SManoj Naik
1340ac34cdb0SJ. Bruce Fields seq_printf(m, ",%s=", loctype);
134193346919SManoj Naik seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
134293346919SManoj Naik seq_putc(m, '@');
134393346919SManoj Naik seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
134493346919SManoj Naik for (i = 1; i < fsloc->locations_count; i++) {
134593346919SManoj Naik seq_putc(m, ';');
134693346919SManoj Naik seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
134793346919SManoj Naik seq_putc(m, '@');
134893346919SManoj Naik seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
134993346919SManoj Naik }
135093346919SManoj Naik }
13511da177e4SLinus Torvalds }
13521da177e4SLinus Torvalds
e_show(struct seq_file * m,void * p)13531da177e4SLinus Torvalds static int e_show(struct seq_file *m, void *p)
13541da177e4SLinus Torvalds {
13551da177e4SLinus Torvalds struct cache_head *cp = p;
13561da177e4SLinus Torvalds struct svc_export *exp = container_of(cp, struct svc_export, h);
1357f2c7ea10SStanislav Kinsbursky struct cache_detail *cd = m->private;
135820ad856eSAmir Goldstein bool export_stats = is_export_stats_file(m);
13591da177e4SLinus Torvalds
1360bc6f02e5SGreg Banks if (p == SEQ_START_TOKEN) {
13611da177e4SLinus Torvalds seq_puts(m, "# Version 1.1\n");
136220ad856eSAmir Goldstein if (export_stats)
136320ad856eSAmir Goldstein seq_puts(m, "# Path Client Start-time\n#\tStats\n");
136420ad856eSAmir Goldstein else
13651da177e4SLinus Torvalds seq_puts(m, "# Path Client(Flags) # IPs\n");
13661da177e4SLinus Torvalds return 0;
13671da177e4SLinus Torvalds }
13681da177e4SLinus Torvalds
13691cecfdbcSYang Erkun if (!cache_get_rcu(&exp->h))
13701cecfdbcSYang Erkun return 0;
13711cecfdbcSYang Erkun
1372f2c7ea10SStanislav Kinsbursky if (cache_check(cd, &exp->h, NULL))
13731da177e4SLinus Torvalds return 0;
13741cecfdbcSYang Erkun
1375a09581f2SStanislav Kinsbursky exp_put(exp);
1376f2c7ea10SStanislav Kinsbursky return svc_export_show(m, cd, cp);
13771da177e4SLinus Torvalds }
13781da177e4SLinus Torvalds
137988e9d34cSJames Morris const struct seq_operations nfs_exports_op = {
13809ceddd9dSTrond Myklebust .start = cache_seq_start_rcu,
13819ceddd9dSTrond Myklebust .next = cache_seq_next_rcu,
13829ceddd9dSTrond Myklebust .stop = cache_seq_stop_rcu,
13831da177e4SLinus Torvalds .show = e_show,
13841da177e4SLinus Torvalds };
13851da177e4SLinus Torvalds
13861da177e4SLinus Torvalds /*
13871da177e4SLinus Torvalds * Initialize the exports module.
13881da177e4SLinus Torvalds */
1389dbf847ecSJ. Bruce Fields int
nfsd_export_init(struct net * net)1390b89109beSStanislav Kinsbursky nfsd_export_init(struct net *net)
13911da177e4SLinus Torvalds {
1392dbf847ecSJ. Bruce Fields int rv;
1393b3853e0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1394b3853e0eSStanislav Kinsbursky
1395ba589528SVasily Averin dprintk("nfsd: initializing export module (net: %x).\n", net->ns.inum);
13961da177e4SLinus Torvalds
1397b3853e0eSStanislav Kinsbursky nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net);
1398b3853e0eSStanislav Kinsbursky if (IS_ERR(nn->svc_export_cache))
1399b3853e0eSStanislav Kinsbursky return PTR_ERR(nn->svc_export_cache);
1400b3853e0eSStanislav Kinsbursky rv = cache_register_net(nn->svc_export_cache, net);
1401dbf847ecSJ. Bruce Fields if (rv)
1402b3853e0eSStanislav Kinsbursky goto destroy_export_cache;
1403b3853e0eSStanislav Kinsbursky
1404e5f06f72SStanislav Kinsbursky nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net);
1405e5f06f72SStanislav Kinsbursky if (IS_ERR(nn->svc_expkey_cache)) {
1406e5f06f72SStanislav Kinsbursky rv = PTR_ERR(nn->svc_expkey_cache);
1407b3853e0eSStanislav Kinsbursky goto unregister_export_cache;
1408e5f06f72SStanislav Kinsbursky }
1409e5f06f72SStanislav Kinsbursky rv = cache_register_net(nn->svc_expkey_cache, net);
1410e5f06f72SStanislav Kinsbursky if (rv)
1411e5f06f72SStanislav Kinsbursky goto destroy_expkey_cache;
1412b3853e0eSStanislav Kinsbursky return 0;
14131da177e4SLinus Torvalds
1414e5f06f72SStanislav Kinsbursky destroy_expkey_cache:
1415e5f06f72SStanislav Kinsbursky cache_destroy_net(nn->svc_expkey_cache, net);
1416b3853e0eSStanislav Kinsbursky unregister_export_cache:
1417b3853e0eSStanislav Kinsbursky cache_unregister_net(nn->svc_export_cache, net);
1418b3853e0eSStanislav Kinsbursky destroy_export_cache:
1419b3853e0eSStanislav Kinsbursky cache_destroy_net(nn->svc_export_cache, net);
1420b3853e0eSStanislav Kinsbursky return rv;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds
14231da177e4SLinus Torvalds /*
14241da177e4SLinus Torvalds * Flush exports table - called when last nfsd thread is killed
14251da177e4SLinus Torvalds */
14261da177e4SLinus Torvalds void
nfsd_export_flush(struct net * net)1427b3853e0eSStanislav Kinsbursky nfsd_export_flush(struct net *net)
14281da177e4SLinus Torvalds {
1429b3853e0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1430b3853e0eSStanislav Kinsbursky
1431e5f06f72SStanislav Kinsbursky cache_purge(nn->svc_expkey_cache);
1432b3853e0eSStanislav Kinsbursky cache_purge(nn->svc_export_cache);
14331da177e4SLinus Torvalds }
14341da177e4SLinus Torvalds
14351da177e4SLinus Torvalds /*
14361da177e4SLinus Torvalds * Shutdown the exports module.
14371da177e4SLinus Torvalds */
14381da177e4SLinus Torvalds void
nfsd_export_shutdown(struct net * net)1439b89109beSStanislav Kinsbursky nfsd_export_shutdown(struct net *net)
14401da177e4SLinus Torvalds {
1441b3853e0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id);
14421da177e4SLinus Torvalds
1443ba589528SVasily Averin dprintk("nfsd: shutting down export module (net: %x).\n", net->ns.inum);
14441da177e4SLinus Torvalds
1445e5f06f72SStanislav Kinsbursky cache_unregister_net(nn->svc_expkey_cache, net);
1446b3853e0eSStanislav Kinsbursky cache_unregister_net(nn->svc_export_cache, net);
1447e5f06f72SStanislav Kinsbursky cache_destroy_net(nn->svc_expkey_cache, net);
1448b3853e0eSStanislav Kinsbursky cache_destroy_net(nn->svc_export_cache, net);
1449e5f06f72SStanislav Kinsbursky svcauth_unix_purge(net);
14501da177e4SLinus Torvalds
1451ba589528SVasily Averin dprintk("nfsd: export shutdown complete (net: %x).\n", net->ns.inum);
14521da177e4SLinus Torvalds }
1453