root/fs/nfsd/export.c

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

DEFINITIONS

This source file includes following definitions.
  1. expkey_put
  2. expkey_request
  3. expkey_parse
  4. expkey_show
  5. expkey_match
  6. expkey_init
  7. expkey_update
  8. expkey_alloc
  9. expkey_flush
  10. svc_expkey_hash
  11. svc_expkey_lookup
  12. svc_expkey_update
  13. nfsd4_fslocs_free
  14. svc_export_put
  15. svc_export_request
  16. check_export
  17. fsloc_parse
  18. secinfo_parse
  19. fsloc_parse
  20. secinfo_parse
  21. nfsd_uuid_parse
  22. svc_export_parse
  23. svc_export_show
  24. svc_export_match
  25. svc_export_init
  26. export_update
  27. svc_export_alloc
  28. svc_export_hash
  29. svc_export_lookup
  30. svc_export_update
  31. exp_find_key
  32. exp_get_by_name
  33. exp_parent
  34. exp_rootfh
  35. exp_find
  36. check_nfsd_access
  37. rqst_exp_get_by_name
  38. rqst_exp_find
  39. rqst_exp_parent
  40. rqst_find_fsidzero_export
  41. exp_pseudoroot
  42. show_expflags
  43. show_secinfo_flags
  44. secinfo_flags_equal
  45. show_secinfo_run
  46. show_secinfo
  47. exp_flags
  48. e_show
  49. nfsd_export_init
  50. nfsd_export_flush
  51. nfsd_export_shutdown

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * NFS exporting and validation.
   4  *
   5  * We maintain a list of clients, each of which has a list of
   6  * exports. To export an fs to a given client, you first have
   7  * to create the client entry with NFSCTL_ADDCLIENT, which
   8  * creates a client control block and adds it to the hash
   9  * table. Then, you call NFSCTL_EXPORT for each fs.
  10  *
  11  *
  12  * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
  13  */
  14 
  15 #include <linux/slab.h>
  16 #include <linux/namei.h>
  17 #include <linux/module.h>
  18 #include <linux/exportfs.h>
  19 #include <linux/sunrpc/svc_xprt.h>
  20 
  21 #include "nfsd.h"
  22 #include "nfsfh.h"
  23 #include "netns.h"
  24 #include "pnfs.h"
  25 #include "filecache.h"
  26 
  27 #define NFSDDBG_FACILITY        NFSDDBG_EXPORT
  28 
  29 /*
  30  * We have two caches.
  31  * One maps client+vfsmnt+dentry to export options - the export map
  32  * The other maps client+filehandle-fragment to export options. - the expkey map
  33  *
  34  * The export options are actually stored in the first map, and the
  35  * second map contains a reference to the entry in the first map.
  36  */
  37 
  38 #define EXPKEY_HASHBITS         8
  39 #define EXPKEY_HASHMAX          (1 << EXPKEY_HASHBITS)
  40 #define EXPKEY_HASHMASK         (EXPKEY_HASHMAX -1)
  41 
  42 static void expkey_put(struct kref *ref)
  43 {
  44         struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
  45 
  46         if (test_bit(CACHE_VALID, &key->h.flags) &&
  47             !test_bit(CACHE_NEGATIVE, &key->h.flags))
  48                 path_put(&key->ek_path);
  49         auth_domain_put(key->ek_client);
  50         kfree_rcu(key, ek_rcu);
  51 }
  52 
  53 static void expkey_request(struct cache_detail *cd,
  54                            struct cache_head *h,
  55                            char **bpp, int *blen)
  56 {
  57         /* client fsidtype \xfsid */
  58         struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
  59         char type[5];
  60 
  61         qword_add(bpp, blen, ek->ek_client->name);
  62         snprintf(type, 5, "%d", ek->ek_fsidtype);
  63         qword_add(bpp, blen, type);
  64         qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
  65         (*bpp)[-1] = '\n';
  66 }
  67 
  68 static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
  69                                             struct svc_expkey *old);
  70 static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
  71 
  72 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
  73 {
  74         /* client fsidtype fsid expiry [path] */
  75         char *buf;
  76         int len;
  77         struct auth_domain *dom = NULL;
  78         int err;
  79         int fsidtype;
  80         char *ep;
  81         struct svc_expkey key;
  82         struct svc_expkey *ek = NULL;
  83 
  84         if (mesg[mlen - 1] != '\n')
  85                 return -EINVAL;
  86         mesg[mlen-1] = 0;
  87 
  88         buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  89         err = -ENOMEM;
  90         if (!buf)
  91                 goto out;
  92 
  93         err = -EINVAL;
  94         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
  95                 goto out;
  96 
  97         err = -ENOENT;
  98         dom = auth_domain_find(buf);
  99         if (!dom)
 100                 goto out;
 101         dprintk("found domain %s\n", buf);
 102 
 103         err = -EINVAL;
 104         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 105                 goto out;
 106         fsidtype = simple_strtoul(buf, &ep, 10);
 107         if (*ep)
 108                 goto out;
 109         dprintk("found fsidtype %d\n", fsidtype);
 110         if (key_len(fsidtype)==0) /* invalid type */
 111                 goto out;
 112         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 113                 goto out;
 114         dprintk("found fsid length %d\n", len);
 115         if (len != key_len(fsidtype))
 116                 goto out;
 117 
 118         /* OK, we seem to have a valid key */
 119         key.h.flags = 0;
 120         key.h.expiry_time = get_expiry(&mesg);
 121         if (key.h.expiry_time == 0)
 122                 goto out;
 123 
 124         key.ek_client = dom;    
 125         key.ek_fsidtype = fsidtype;
 126         memcpy(key.ek_fsid, buf, len);
 127 
 128         ek = svc_expkey_lookup(cd, &key);
 129         err = -ENOMEM;
 130         if (!ek)
 131                 goto out;
 132 
 133         /* now we want a pathname, or empty meaning NEGATIVE  */
 134         err = -EINVAL;
 135         len = qword_get(&mesg, buf, PAGE_SIZE);
 136         if (len < 0)
 137                 goto out;
 138         dprintk("Path seems to be <%s>\n", buf);
 139         err = 0;
 140         if (len == 0) {
 141                 set_bit(CACHE_NEGATIVE, &key.h.flags);
 142                 ek = svc_expkey_update(cd, &key, ek);
 143                 if (!ek)
 144                         err = -ENOMEM;
 145         } else {
 146                 err = kern_path(buf, 0, &key.ek_path);
 147                 if (err)
 148                         goto out;
 149 
 150                 dprintk("Found the path %s\n", buf);
 151 
 152                 ek = svc_expkey_update(cd, &key, ek);
 153                 if (!ek)
 154                         err = -ENOMEM;
 155                 path_put(&key.ek_path);
 156         }
 157         cache_flush();
 158  out:
 159         if (ek)
 160                 cache_put(&ek->h, cd);
 161         if (dom)
 162                 auth_domain_put(dom);
 163         kfree(buf);
 164         return err;
 165 }
 166 
 167 static int expkey_show(struct seq_file *m,
 168                        struct cache_detail *cd,
 169                        struct cache_head *h)
 170 {
 171         struct svc_expkey *ek ;
 172         int i;
 173 
 174         if (h ==NULL) {
 175                 seq_puts(m, "#domain fsidtype fsid [path]\n");
 176                 return 0;
 177         }
 178         ek = container_of(h, struct svc_expkey, h);
 179         seq_printf(m, "%s %d 0x", ek->ek_client->name,
 180                    ek->ek_fsidtype);
 181         for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
 182                 seq_printf(m, "%08x", ek->ek_fsid[i]);
 183         if (test_bit(CACHE_VALID, &h->flags) && 
 184             !test_bit(CACHE_NEGATIVE, &h->flags)) {
 185                 seq_printf(m, " ");
 186                 seq_path(m, &ek->ek_path, "\\ \t\n");
 187         }
 188         seq_printf(m, "\n");
 189         return 0;
 190 }
 191 
 192 static inline int expkey_match (struct cache_head *a, struct cache_head *b)
 193 {
 194         struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
 195         struct svc_expkey *new = container_of(b, struct svc_expkey, h);
 196 
 197         if (orig->ek_fsidtype != new->ek_fsidtype ||
 198             orig->ek_client != new->ek_client ||
 199             memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
 200                 return 0;
 201         return 1;
 202 }
 203 
 204 static inline void expkey_init(struct cache_head *cnew,
 205                                    struct cache_head *citem)
 206 {
 207         struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
 208         struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 209 
 210         kref_get(&item->ek_client->ref);
 211         new->ek_client = item->ek_client;
 212         new->ek_fsidtype = item->ek_fsidtype;
 213 
 214         memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
 215 }
 216 
 217 static inline void expkey_update(struct cache_head *cnew,
 218                                    struct cache_head *citem)
 219 {
 220         struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
 221         struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 222 
 223         new->ek_path = item->ek_path;
 224         path_get(&item->ek_path);
 225 }
 226 
 227 static struct cache_head *expkey_alloc(void)
 228 {
 229         struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
 230         if (i)
 231                 return &i->h;
 232         else
 233                 return NULL;
 234 }
 235 
 236 static void expkey_flush(void)
 237 {
 238         /*
 239          * Take the nfsd_mutex here to ensure that the file cache is not
 240          * destroyed while we're in the middle of flushing.
 241          */
 242         mutex_lock(&nfsd_mutex);
 243         nfsd_file_cache_purge(current->nsproxy->net_ns);
 244         mutex_unlock(&nfsd_mutex);
 245 }
 246 
 247 static const struct cache_detail svc_expkey_cache_template = {
 248         .owner          = THIS_MODULE,
 249         .hash_size      = EXPKEY_HASHMAX,
 250         .name           = "nfsd.fh",
 251         .cache_put      = expkey_put,
 252         .cache_request  = expkey_request,
 253         .cache_parse    = expkey_parse,
 254         .cache_show     = expkey_show,
 255         .match          = expkey_match,
 256         .init           = expkey_init,
 257         .update         = expkey_update,
 258         .alloc          = expkey_alloc,
 259         .flush          = expkey_flush,
 260 };
 261 
 262 static int
 263 svc_expkey_hash(struct svc_expkey *item)
 264 {
 265         int hash = item->ek_fsidtype;
 266         char * cp = (char*)item->ek_fsid;
 267         int len = key_len(item->ek_fsidtype);
 268 
 269         hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
 270         hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
 271         hash &= EXPKEY_HASHMASK;
 272         return hash;
 273 }
 274 
 275 static struct svc_expkey *
 276 svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
 277 {
 278         struct cache_head *ch;
 279         int hash = svc_expkey_hash(item);
 280 
 281         ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash);
 282         if (ch)
 283                 return container_of(ch, struct svc_expkey, h);
 284         else
 285                 return NULL;
 286 }
 287 
 288 static struct svc_expkey *
 289 svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
 290                   struct svc_expkey *old)
 291 {
 292         struct cache_head *ch;
 293         int hash = svc_expkey_hash(new);
 294 
 295         ch = sunrpc_cache_update(cd, &new->h, &old->h, hash);
 296         if (ch)
 297                 return container_of(ch, struct svc_expkey, h);
 298         else
 299                 return NULL;
 300 }
 301 
 302 
 303 #define EXPORT_HASHBITS         8
 304 #define EXPORT_HASHMAX          (1<< EXPORT_HASHBITS)
 305 
 306 static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
 307 {
 308         struct nfsd4_fs_location *locations = fsloc->locations;
 309         int i;
 310 
 311         if (!locations)
 312                 return;
 313 
 314         for (i = 0; i < fsloc->locations_count; i++) {
 315                 kfree(locations[i].path);
 316                 kfree(locations[i].hosts);
 317         }
 318 
 319         kfree(locations);
 320         fsloc->locations = NULL;
 321 }
 322 
 323 static void svc_export_put(struct kref *ref)
 324 {
 325         struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
 326         path_put(&exp->ex_path);
 327         auth_domain_put(exp->ex_client);
 328         nfsd4_fslocs_free(&exp->ex_fslocs);
 329         kfree(exp->ex_uuid);
 330         kfree_rcu(exp, ex_rcu);
 331 }
 332 
 333 static void svc_export_request(struct cache_detail *cd,
 334                                struct cache_head *h,
 335                                char **bpp, int *blen)
 336 {
 337         /*  client path */
 338         struct svc_export *exp = container_of(h, struct svc_export, h);
 339         char *pth;
 340 
 341         qword_add(bpp, blen, exp->ex_client->name);
 342         pth = d_path(&exp->ex_path, *bpp, *blen);
 343         if (IS_ERR(pth)) {
 344                 /* is this correct? */
 345                 (*bpp)[0] = '\n';
 346                 return;
 347         }
 348         qword_add(bpp, blen, pth);
 349         (*bpp)[-1] = '\n';
 350 }
 351 
 352 static struct svc_export *svc_export_update(struct svc_export *new,
 353                                             struct svc_export *old);
 354 static struct svc_export *svc_export_lookup(struct svc_export *);
 355 
 356 static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
 357 {
 358 
 359         /*
 360          * We currently export only dirs, regular files, and (for v4
 361          * pseudoroot) symlinks.
 362          */
 363         if (!S_ISDIR(inode->i_mode) &&
 364             !S_ISLNK(inode->i_mode) &&
 365             !S_ISREG(inode->i_mode))
 366                 return -ENOTDIR;
 367 
 368         /*
 369          * Mountd should never pass down a writeable V4ROOT export, but,
 370          * just to make sure:
 371          */
 372         if (*flags & NFSEXP_V4ROOT)
 373                 *flags |= NFSEXP_READONLY;
 374 
 375         /* There are two requirements on a filesystem to be exportable.
 376          * 1:  We must be able to identify the filesystem from a number.
 377          *       either a device number (so FS_REQUIRES_DEV needed)
 378          *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
 379          * 2:  We must be able to find an inode from a filehandle.
 380          *       This means that s_export_op must be set.
 381          */
 382         if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
 383             !(*flags & NFSEXP_FSID) &&
 384             uuid == NULL) {
 385                 dprintk("exp_export: export of non-dev fs without fsid\n");
 386                 return -EINVAL;
 387         }
 388 
 389         if (!inode->i_sb->s_export_op ||
 390             !inode->i_sb->s_export_op->fh_to_dentry) {
 391                 dprintk("exp_export: export of invalid fs type.\n");
 392                 return -EINVAL;
 393         }
 394 
 395         return 0;
 396 
 397 }
 398 
 399 #ifdef CONFIG_NFSD_V4
 400 
 401 static int
 402 fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
 403 {
 404         int len;
 405         int migrated, i, err;
 406 
 407         /* more than one fsloc */
 408         if (fsloc->locations)
 409                 return -EINVAL;
 410 
 411         /* listsize */
 412         err = get_uint(mesg, &fsloc->locations_count);
 413         if (err)
 414                 return err;
 415         if (fsloc->locations_count > MAX_FS_LOCATIONS)
 416                 return -EINVAL;
 417         if (fsloc->locations_count == 0)
 418                 return 0;
 419 
 420         fsloc->locations = kcalloc(fsloc->locations_count,
 421                                    sizeof(struct nfsd4_fs_location),
 422                                    GFP_KERNEL);
 423         if (!fsloc->locations)
 424                 return -ENOMEM;
 425         for (i=0; i < fsloc->locations_count; i++) {
 426                 /* colon separated host list */
 427                 err = -EINVAL;
 428                 len = qword_get(mesg, buf, PAGE_SIZE);
 429                 if (len <= 0)
 430                         goto out_free_all;
 431                 err = -ENOMEM;
 432                 fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
 433                 if (!fsloc->locations[i].hosts)
 434                         goto out_free_all;
 435                 err = -EINVAL;
 436                 /* slash separated path component list */
 437                 len = qword_get(mesg, buf, PAGE_SIZE);
 438                 if (len <= 0)
 439                         goto out_free_all;
 440                 err = -ENOMEM;
 441                 fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
 442                 if (!fsloc->locations[i].path)
 443                         goto out_free_all;
 444         }
 445         /* migrated */
 446         err = get_int(mesg, &migrated);
 447         if (err)
 448                 goto out_free_all;
 449         err = -EINVAL;
 450         if (migrated < 0 || migrated > 1)
 451                 goto out_free_all;
 452         fsloc->migrated = migrated;
 453         return 0;
 454 out_free_all:
 455         nfsd4_fslocs_free(fsloc);
 456         return err;
 457 }
 458 
 459 static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
 460 {
 461         struct exp_flavor_info *f;
 462         u32 listsize;
 463         int err;
 464 
 465         /* more than one secinfo */
 466         if (exp->ex_nflavors)
 467                 return -EINVAL;
 468 
 469         err = get_uint(mesg, &listsize);
 470         if (err)
 471                 return err;
 472         if (listsize > MAX_SECINFO_LIST)
 473                 return -EINVAL;
 474 
 475         for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
 476                 err = get_uint(mesg, &f->pseudoflavor);
 477                 if (err)
 478                         return err;
 479                 /*
 480                  * XXX: It would be nice to also check whether this
 481                  * pseudoflavor is supported, so we can discover the
 482                  * problem at export time instead of when a client fails
 483                  * to authenticate.
 484                  */
 485                 err = get_uint(mesg, &f->flags);
 486                 if (err)
 487                         return err;
 488                 /* Only some flags are allowed to differ between flavors: */
 489                 if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
 490                         return -EINVAL;
 491         }
 492         exp->ex_nflavors = listsize;
 493         return 0;
 494 }
 495 
 496 #else /* CONFIG_NFSD_V4 */
 497 static inline int
 498 fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
 499 static inline int
 500 secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
 501 #endif
 502 
 503 static inline int
 504 nfsd_uuid_parse(char **mesg, char *buf, unsigned char **puuid)
 505 {
 506         int len;
 507 
 508         /* more than one uuid */
 509         if (*puuid)
 510                 return -EINVAL;
 511 
 512         /* expect a 16 byte uuid encoded as \xXXXX... */
 513         len = qword_get(mesg, buf, PAGE_SIZE);
 514         if (len != EX_UUID_LEN)
 515                 return -EINVAL;
 516 
 517         *puuid = kmemdup(buf, EX_UUID_LEN, GFP_KERNEL);
 518         if (*puuid == NULL)
 519                 return -ENOMEM;
 520 
 521         return 0;
 522 }
 523 
 524 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
 525 {
 526         /* client path expiry [flags anonuid anongid fsid] */
 527         char *buf;
 528         int len;
 529         int err;
 530         struct auth_domain *dom = NULL;
 531         struct svc_export exp = {}, *expp;
 532         int an_int;
 533 
 534         if (mesg[mlen-1] != '\n')
 535                 return -EINVAL;
 536         mesg[mlen-1] = 0;
 537 
 538         buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 539         if (!buf)
 540                 return -ENOMEM;
 541 
 542         /* client */
 543         err = -EINVAL;
 544         len = qword_get(&mesg, buf, PAGE_SIZE);
 545         if (len <= 0)
 546                 goto out;
 547 
 548         err = -ENOENT;
 549         dom = auth_domain_find(buf);
 550         if (!dom)
 551                 goto out;
 552 
 553         /* path */
 554         err = -EINVAL;
 555         if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 556                 goto out1;
 557 
 558         err = kern_path(buf, 0, &exp.ex_path);
 559         if (err)
 560                 goto out1;
 561 
 562         exp.ex_client = dom;
 563         exp.cd = cd;
 564         exp.ex_devid_map = NULL;
 565 
 566         /* expiry */
 567         err = -EINVAL;
 568         exp.h.expiry_time = get_expiry(&mesg);
 569         if (exp.h.expiry_time == 0)
 570                 goto out3;
 571 
 572         /* flags */
 573         err = get_int(&mesg, &an_int);
 574         if (err == -ENOENT) {
 575                 err = 0;
 576                 set_bit(CACHE_NEGATIVE, &exp.h.flags);
 577         } else {
 578                 if (err || an_int < 0)
 579                         goto out3;
 580                 exp.ex_flags= an_int;
 581         
 582                 /* anon uid */
 583                 err = get_int(&mesg, &an_int);
 584                 if (err)
 585                         goto out3;
 586                 exp.ex_anon_uid= make_kuid(current_user_ns(), an_int);
 587 
 588                 /* anon gid */
 589                 err = get_int(&mesg, &an_int);
 590                 if (err)
 591                         goto out3;
 592                 exp.ex_anon_gid= make_kgid(current_user_ns(), an_int);
 593 
 594                 /* fsid */
 595                 err = get_int(&mesg, &an_int);
 596                 if (err)
 597                         goto out3;
 598                 exp.ex_fsid = an_int;
 599 
 600                 while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
 601                         if (strcmp(buf, "fsloc") == 0)
 602                                 err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
 603                         else if (strcmp(buf, "uuid") == 0)
 604                                 err = nfsd_uuid_parse(&mesg, buf, &exp.ex_uuid);
 605                         else if (strcmp(buf, "secinfo") == 0)
 606                                 err = secinfo_parse(&mesg, buf, &exp);
 607                         else
 608                                 /* quietly ignore unknown words and anything
 609                                  * following. Newer user-space can try to set
 610                                  * new values, then see what the result was.
 611                                  */
 612                                 break;
 613                         if (err)
 614                                 goto out4;
 615                 }
 616 
 617                 err = check_export(d_inode(exp.ex_path.dentry), &exp.ex_flags,
 618                                    exp.ex_uuid);
 619                 if (err)
 620                         goto out4;
 621                 /*
 622                  * No point caching this if it would immediately expire.
 623                  * Also, this protects exportfs's dummy export from the
 624                  * anon_uid/anon_gid checks:
 625                  */
 626                 if (exp.h.expiry_time < seconds_since_boot())
 627                         goto out4;
 628                 /*
 629                  * For some reason exportfs has been passing down an
 630                  * invalid (-1) uid & gid on the "dummy" export which it
 631                  * uses to test export support.  To make sure exportfs
 632                  * sees errors from check_export we therefore need to
 633                  * delay these checks till after check_export:
 634                  */
 635                 err = -EINVAL;
 636                 if (!uid_valid(exp.ex_anon_uid))
 637                         goto out4;
 638                 if (!gid_valid(exp.ex_anon_gid))
 639                         goto out4;
 640                 err = 0;
 641 
 642                 nfsd4_setup_layout_type(&exp);
 643         }
 644 
 645         expp = svc_export_lookup(&exp);
 646         if (expp)
 647                 expp = svc_export_update(&exp, expp);
 648         else
 649                 err = -ENOMEM;
 650         cache_flush();
 651         if (expp == NULL)
 652                 err = -ENOMEM;
 653         else
 654                 exp_put(expp);
 655 out4:
 656         nfsd4_fslocs_free(&exp.ex_fslocs);
 657         kfree(exp.ex_uuid);
 658 out3:
 659         path_put(&exp.ex_path);
 660 out1:
 661         auth_domain_put(dom);
 662 out:
 663         kfree(buf);
 664         return err;
 665 }
 666 
 667 static void exp_flags(struct seq_file *m, int flag, int fsid,
 668                 kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);
 669 static void show_secinfo(struct seq_file *m, struct svc_export *exp);
 670 
 671 static int svc_export_show(struct seq_file *m,
 672                            struct cache_detail *cd,
 673                            struct cache_head *h)
 674 {
 675         struct svc_export *exp ;
 676 
 677         if (h ==NULL) {
 678                 seq_puts(m, "#path domain(flags)\n");
 679                 return 0;
 680         }
 681         exp = container_of(h, struct svc_export, h);
 682         seq_path(m, &exp->ex_path, " \t\n\\");
 683         seq_putc(m, '\t');
 684         seq_escape(m, exp->ex_client->name, " \t\n\\");
 685         seq_putc(m, '(');
 686         if (test_bit(CACHE_VALID, &h->flags) && 
 687             !test_bit(CACHE_NEGATIVE, &h->flags)) {
 688                 exp_flags(m, exp->ex_flags, exp->ex_fsid,
 689                           exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
 690                 if (exp->ex_uuid) {
 691                         int i;
 692                         seq_puts(m, ",uuid=");
 693                         for (i = 0; i < EX_UUID_LEN; i++) {
 694                                 if ((i&3) == 0 && i)
 695                                         seq_putc(m, ':');
 696                                 seq_printf(m, "%02x", exp->ex_uuid[i]);
 697                         }
 698                 }
 699                 show_secinfo(m, exp);
 700         }
 701         seq_puts(m, ")\n");
 702         return 0;
 703 }
 704 static int svc_export_match(struct cache_head *a, struct cache_head *b)
 705 {
 706         struct svc_export *orig = container_of(a, struct svc_export, h);
 707         struct svc_export *new = container_of(b, struct svc_export, h);
 708         return orig->ex_client == new->ex_client &&
 709                 path_equal(&orig->ex_path, &new->ex_path);
 710 }
 711 
 712 static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
 713 {
 714         struct svc_export *new = container_of(cnew, struct svc_export, h);
 715         struct svc_export *item = container_of(citem, struct svc_export, h);
 716 
 717         kref_get(&item->ex_client->ref);
 718         new->ex_client = item->ex_client;
 719         new->ex_path = item->ex_path;
 720         path_get(&item->ex_path);
 721         new->ex_fslocs.locations = NULL;
 722         new->ex_fslocs.locations_count = 0;
 723         new->ex_fslocs.migrated = 0;
 724         new->ex_layout_types = 0;
 725         new->ex_uuid = NULL;
 726         new->cd = item->cd;
 727 }
 728 
 729 static void export_update(struct cache_head *cnew, struct cache_head *citem)
 730 {
 731         struct svc_export *new = container_of(cnew, struct svc_export, h);
 732         struct svc_export *item = container_of(citem, struct svc_export, h);
 733         int i;
 734 
 735         new->ex_flags = item->ex_flags;
 736         new->ex_anon_uid = item->ex_anon_uid;
 737         new->ex_anon_gid = item->ex_anon_gid;
 738         new->ex_fsid = item->ex_fsid;
 739         new->ex_devid_map = item->ex_devid_map;
 740         item->ex_devid_map = NULL;
 741         new->ex_uuid = item->ex_uuid;
 742         item->ex_uuid = NULL;
 743         new->ex_fslocs.locations = item->ex_fslocs.locations;
 744         item->ex_fslocs.locations = NULL;
 745         new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
 746         item->ex_fslocs.locations_count = 0;
 747         new->ex_fslocs.migrated = item->ex_fslocs.migrated;
 748         item->ex_fslocs.migrated = 0;
 749         new->ex_layout_types = item->ex_layout_types;
 750         new->ex_nflavors = item->ex_nflavors;
 751         for (i = 0; i < MAX_SECINFO_LIST; i++) {
 752                 new->ex_flavors[i] = item->ex_flavors[i];
 753         }
 754 }
 755 
 756 static struct cache_head *svc_export_alloc(void)
 757 {
 758         struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
 759         if (i)
 760                 return &i->h;
 761         else
 762                 return NULL;
 763 }
 764 
 765 static const struct cache_detail svc_export_cache_template = {
 766         .owner          = THIS_MODULE,
 767         .hash_size      = EXPORT_HASHMAX,
 768         .name           = "nfsd.export",
 769         .cache_put      = svc_export_put,
 770         .cache_request  = svc_export_request,
 771         .cache_parse    = svc_export_parse,
 772         .cache_show     = svc_export_show,
 773         .match          = svc_export_match,
 774         .init           = svc_export_init,
 775         .update         = export_update,
 776         .alloc          = svc_export_alloc,
 777 };
 778 
 779 static int
 780 svc_export_hash(struct svc_export *exp)
 781 {
 782         int hash;
 783 
 784         hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
 785         hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
 786         hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
 787         return hash;
 788 }
 789 
 790 static struct svc_export *
 791 svc_export_lookup(struct svc_export *exp)
 792 {
 793         struct cache_head *ch;
 794         int hash = svc_export_hash(exp);
 795 
 796         ch = sunrpc_cache_lookup_rcu(exp->cd, &exp->h, hash);
 797         if (ch)
 798                 return container_of(ch, struct svc_export, h);
 799         else
 800                 return NULL;
 801 }
 802 
 803 static struct svc_export *
 804 svc_export_update(struct svc_export *new, struct svc_export *old)
 805 {
 806         struct cache_head *ch;
 807         int hash = svc_export_hash(old);
 808 
 809         ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash);
 810         if (ch)
 811                 return container_of(ch, struct svc_export, h);
 812         else
 813                 return NULL;
 814 }
 815 
 816 
 817 static struct svc_expkey *
 818 exp_find_key(struct cache_detail *cd, struct auth_domain *clp, int fsid_type,
 819              u32 *fsidv, struct cache_req *reqp)
 820 {
 821         struct svc_expkey key, *ek;
 822         int err;
 823         
 824         if (!clp)
 825                 return ERR_PTR(-ENOENT);
 826 
 827         key.ek_client = clp;
 828         key.ek_fsidtype = fsid_type;
 829         memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
 830 
 831         ek = svc_expkey_lookup(cd, &key);
 832         if (ek == NULL)
 833                 return ERR_PTR(-ENOMEM);
 834         err = cache_check(cd, &ek->h, reqp);
 835         if (err)
 836                 return ERR_PTR(err);
 837         return ek;
 838 }
 839 
 840 static struct svc_export *
 841 exp_get_by_name(struct cache_detail *cd, struct auth_domain *clp,
 842                 const struct path *path, struct cache_req *reqp)
 843 {
 844         struct svc_export *exp, key;
 845         int err;
 846 
 847         if (!clp)
 848                 return ERR_PTR(-ENOENT);
 849 
 850         key.ex_client = clp;
 851         key.ex_path = *path;
 852         key.cd = cd;
 853 
 854         exp = svc_export_lookup(&key);
 855         if (exp == NULL)
 856                 return ERR_PTR(-ENOMEM);
 857         err = cache_check(cd, &exp->h, reqp);
 858         if (err)
 859                 return ERR_PTR(err);
 860         return exp;
 861 }
 862 
 863 /*
 864  * Find the export entry for a given dentry.
 865  */
 866 static struct svc_export *
 867 exp_parent(struct cache_detail *cd, struct auth_domain *clp, struct path *path)
 868 {
 869         struct dentry *saved = dget(path->dentry);
 870         struct svc_export *exp = exp_get_by_name(cd, clp, path, NULL);
 871 
 872         while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
 873                 struct dentry *parent = dget_parent(path->dentry);
 874                 dput(path->dentry);
 875                 path->dentry = parent;
 876                 exp = exp_get_by_name(cd, clp, path, NULL);
 877         }
 878         dput(path->dentry);
 879         path->dentry = saved;
 880         return exp;
 881 }
 882 
 883 
 884 
 885 /*
 886  * Obtain the root fh on behalf of a client.
 887  * This could be done in user space, but I feel that it adds some safety
 888  * since its harder to fool a kernel module than a user space program.
 889  */
 890 int
 891 exp_rootfh(struct net *net, struct auth_domain *clp, char *name,
 892            struct knfsd_fh *f, int maxsize)
 893 {
 894         struct svc_export       *exp;
 895         struct path             path;
 896         struct inode            *inode;
 897         struct svc_fh           fh;
 898         int                     err;
 899         struct nfsd_net         *nn = net_generic(net, nfsd_net_id);
 900         struct cache_detail     *cd = nn->svc_export_cache;
 901 
 902         err = -EPERM;
 903         /* NB: we probably ought to check that it's NUL-terminated */
 904         if (kern_path(name, 0, &path)) {
 905                 printk("nfsd: exp_rootfh path not found %s", name);
 906                 return err;
 907         }
 908         inode = d_inode(path.dentry);
 909 
 910         dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
 911                  name, path.dentry, clp->name,
 912                  inode->i_sb->s_id, inode->i_ino);
 913         exp = exp_parent(cd, clp, &path);
 914         if (IS_ERR(exp)) {
 915                 err = PTR_ERR(exp);
 916                 goto out;
 917         }
 918 
 919         /*
 920          * fh must be initialized before calling fh_compose
 921          */
 922         fh_init(&fh, maxsize);
 923         if (fh_compose(&fh, exp, path.dentry, NULL))
 924                 err = -EINVAL;
 925         else
 926                 err = 0;
 927         memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
 928         fh_put(&fh);
 929         exp_put(exp);
 930 out:
 931         path_put(&path);
 932         return err;
 933 }
 934 
 935 static struct svc_export *exp_find(struct cache_detail *cd,
 936                                    struct auth_domain *clp, int fsid_type,
 937                                    u32 *fsidv, struct cache_req *reqp)
 938 {
 939         struct svc_export *exp;
 940         struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id);
 941         struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp);
 942         if (IS_ERR(ek))
 943                 return ERR_CAST(ek);
 944 
 945         exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp);
 946         cache_put(&ek->h, nn->svc_expkey_cache);
 947 
 948         if (IS_ERR(exp))
 949                 return ERR_CAST(exp);
 950         return exp;
 951 }
 952 
 953 __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
 954 {
 955         struct exp_flavor_info *f;
 956         struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
 957 
 958         /* legacy gss-only clients are always OK: */
 959         if (exp->ex_client == rqstp->rq_gssclient)
 960                 return 0;
 961         /* ip-address based client; check sec= export option: */
 962         for (f = exp->ex_flavors; f < end; f++) {
 963                 if (f->pseudoflavor == rqstp->rq_cred.cr_flavor)
 964                         return 0;
 965         }
 966         /* defaults in absence of sec= options: */
 967         if (exp->ex_nflavors == 0) {
 968                 if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
 969                     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
 970                         return 0;
 971         }
 972 
 973         /* If the compound op contains a spo_must_allowed op,
 974          * it will be sent with integrity/protection which
 975          * will have to be expressly allowed on mounts that
 976          * don't support it
 977          */
 978 
 979         if (nfsd4_spo_must_allow(rqstp))
 980                 return 0;
 981 
 982         return nfserr_wrongsec;
 983 }
 984 
 985 /*
 986  * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
 987  * auth_unix client) if it's available and has secinfo information;
 988  * otherwise, will try to use rq_gssclient.
 989  *
 990  * Called from functions that handle requests; functions that do work on
 991  * behalf of mountd are passed a single client name to use, and should
 992  * use exp_get_by_name() or exp_find().
 993  */
 994 struct svc_export *
 995 rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
 996 {
 997         struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
 998         struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 999         struct cache_detail *cd = nn->svc_export_cache;
1000 
1001         if (rqstp->rq_client == NULL)
1002                 goto gss;
1003 
1004         /* First try the auth_unix client: */
1005         exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle);
1006         if (PTR_ERR(exp) == -ENOENT)
1007                 goto gss;
1008         if (IS_ERR(exp))
1009                 return exp;
1010         /* If it has secinfo, assume there are no gss/... clients */
1011         if (exp->ex_nflavors > 0)
1012                 return exp;
1013 gss:
1014         /* Otherwise, try falling back on gss client */
1015         if (rqstp->rq_gssclient == NULL)
1016                 return exp;
1017         gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle);
1018         if (PTR_ERR(gssexp) == -ENOENT)
1019                 return exp;
1020         if (!IS_ERR(exp))
1021                 exp_put(exp);
1022         return gssexp;
1023 }
1024 
1025 struct svc_export *
1026 rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
1027 {
1028         struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1029         struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1030         struct cache_detail *cd = nn->svc_export_cache;
1031 
1032         if (rqstp->rq_client == NULL)
1033                 goto gss;
1034 
1035         /* First try the auth_unix client: */
1036         exp = exp_find(cd, rqstp->rq_client, fsid_type,
1037                        fsidv, &rqstp->rq_chandle);
1038         if (PTR_ERR(exp) == -ENOENT)
1039                 goto gss;
1040         if (IS_ERR(exp))
1041                 return exp;
1042         /* If it has secinfo, assume there are no gss/... clients */
1043         if (exp->ex_nflavors > 0)
1044                 return exp;
1045 gss:
1046         /* Otherwise, try falling back on gss client */
1047         if (rqstp->rq_gssclient == NULL)
1048                 return exp;
1049         gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv,
1050                                                 &rqstp->rq_chandle);
1051         if (PTR_ERR(gssexp) == -ENOENT)
1052                 return exp;
1053         if (!IS_ERR(exp))
1054                 exp_put(exp);
1055         return gssexp;
1056 }
1057 
1058 struct svc_export *
1059 rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
1060 {
1061         struct dentry *saved = dget(path->dentry);
1062         struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
1063 
1064         while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
1065                 struct dentry *parent = dget_parent(path->dentry);
1066                 dput(path->dentry);
1067                 path->dentry = parent;
1068                 exp = rqst_exp_get_by_name(rqstp, path);
1069         }
1070         dput(path->dentry);
1071         path->dentry = saved;
1072         return exp;
1073 }
1074 
1075 struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
1076 {
1077         u32 fsidv[2];
1078 
1079         mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1080 
1081         return rqst_exp_find(rqstp, FSID_NUM, fsidv);
1082 }
1083 
1084 /*
1085  * Called when we need the filehandle for the root of the pseudofs,
1086  * for a given NFSv4 client.   The root is defined to be the
1087  * export point with fsid==0
1088  */
1089 __be32
1090 exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1091 {
1092         struct svc_export *exp;
1093         __be32 rv;
1094 
1095         exp = rqst_find_fsidzero_export(rqstp);
1096         if (IS_ERR(exp))
1097                 return nfserrno(PTR_ERR(exp));
1098         rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
1099         exp_put(exp);
1100         return rv;
1101 }
1102 
1103 static struct flags {
1104         int flag;
1105         char *name[2];
1106 } expflags[] = {
1107         { NFSEXP_READONLY, {"ro", "rw"}},
1108         { NFSEXP_INSECURE_PORT, {"insecure", ""}},
1109         { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
1110         { NFSEXP_ALLSQUASH, {"all_squash", ""}},
1111         { NFSEXP_ASYNC, {"async", "sync"}},
1112         { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
1113         { NFSEXP_NOREADDIRPLUS, {"nordirplus", ""}},
1114         { NFSEXP_NOHIDE, {"nohide", ""}},
1115         { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
1116         { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
1117         { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1118         { NFSEXP_V4ROOT, {"v4root", ""}},
1119         { NFSEXP_PNFS, {"pnfs", ""}},
1120         { NFSEXP_SECURITY_LABEL, {"security_label", ""}},
1121         { 0, {"", ""}}
1122 };
1123 
1124 static void show_expflags(struct seq_file *m, int flags, int mask)
1125 {
1126         struct flags *flg;
1127         int state, first = 0;
1128 
1129         for (flg = expflags; flg->flag; flg++) {
1130                 if (flg->flag & ~mask)
1131                         continue;
1132                 state = (flg->flag & flags) ? 0 : 1;
1133                 if (*flg->name[state])
1134                         seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1135         }
1136 }
1137 
1138 static void show_secinfo_flags(struct seq_file *m, int flags)
1139 {
1140         seq_printf(m, ",");
1141         show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1142 }
1143 
1144 static bool secinfo_flags_equal(int f, int g)
1145 {
1146         f &= NFSEXP_SECINFO_FLAGS;
1147         g &= NFSEXP_SECINFO_FLAGS;
1148         return f == g;
1149 }
1150 
1151 static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
1152 {
1153         int flags;
1154 
1155         flags = (*fp)->flags;
1156         seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
1157         (*fp)++;
1158         while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
1159                 seq_printf(m, ":%d", (*fp)->pseudoflavor);
1160                 (*fp)++;
1161         }
1162         return flags;
1163 }
1164 
1165 static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1166 {
1167         struct exp_flavor_info *f;
1168         struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1169         int flags;
1170 
1171         if (exp->ex_nflavors == 0)
1172                 return;
1173         f = exp->ex_flavors;
1174         flags = show_secinfo_run(m, &f, end);
1175         if (!secinfo_flags_equal(flags, exp->ex_flags))
1176                 show_secinfo_flags(m, flags);
1177         while (f != end) {
1178                 flags = show_secinfo_run(m, &f, end);
1179                 show_secinfo_flags(m, flags);
1180         }
1181 }
1182 
1183 static void exp_flags(struct seq_file *m, int flag, int fsid,
1184                 kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
1185 {
1186         struct user_namespace *userns = m->file->f_cred->user_ns;
1187 
1188         show_expflags(m, flag, NFSEXP_ALLFLAGS);
1189         if (flag & NFSEXP_FSID)
1190                 seq_printf(m, ",fsid=%d", fsid);
1191         if (!uid_eq(anonu, make_kuid(userns, (uid_t)-2)) &&
1192             !uid_eq(anonu, make_kuid(userns, 0x10000-2)))
1193                 seq_printf(m, ",anonuid=%u", from_kuid_munged(userns, anonu));
1194         if (!gid_eq(anong, make_kgid(userns, (gid_t)-2)) &&
1195             !gid_eq(anong, make_kgid(userns, 0x10000-2)))
1196                 seq_printf(m, ",anongid=%u", from_kgid_munged(userns, anong));
1197         if (fsloc && fsloc->locations_count > 0) {
1198                 char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1199                 int i;
1200 
1201                 seq_printf(m, ",%s=", loctype);
1202                 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1203                 seq_putc(m, '@');
1204                 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
1205                 for (i = 1; i < fsloc->locations_count; i++) {
1206                         seq_putc(m, ';');
1207                         seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
1208                         seq_putc(m, '@');
1209                         seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
1210                 }
1211         }
1212 }
1213 
1214 static int e_show(struct seq_file *m, void *p)
1215 {
1216         struct cache_head *cp = p;
1217         struct svc_export *exp = container_of(cp, struct svc_export, h);
1218         struct cache_detail *cd = m->private;
1219 
1220         if (p == SEQ_START_TOKEN) {
1221                 seq_puts(m, "# Version 1.1\n");
1222                 seq_puts(m, "# Path Client(Flags) # IPs\n");
1223                 return 0;
1224         }
1225 
1226         exp_get(exp);
1227         if (cache_check(cd, &exp->h, NULL))
1228                 return 0;
1229         exp_put(exp);
1230         return svc_export_show(m, cd, cp);
1231 }
1232 
1233 const struct seq_operations nfs_exports_op = {
1234         .start  = cache_seq_start_rcu,
1235         .next   = cache_seq_next_rcu,
1236         .stop   = cache_seq_stop_rcu,
1237         .show   = e_show,
1238 };
1239 
1240 /*
1241  * Initialize the exports module.
1242  */
1243 int
1244 nfsd_export_init(struct net *net)
1245 {
1246         int rv;
1247         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1248 
1249         dprintk("nfsd: initializing export module (net: %x).\n", net->ns.inum);
1250 
1251         nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net);
1252         if (IS_ERR(nn->svc_export_cache))
1253                 return PTR_ERR(nn->svc_export_cache);
1254         rv = cache_register_net(nn->svc_export_cache, net);
1255         if (rv)
1256                 goto destroy_export_cache;
1257 
1258         nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net);
1259         if (IS_ERR(nn->svc_expkey_cache)) {
1260                 rv = PTR_ERR(nn->svc_expkey_cache);
1261                 goto unregister_export_cache;
1262         }
1263         rv = cache_register_net(nn->svc_expkey_cache, net);
1264         if (rv)
1265                 goto destroy_expkey_cache;
1266         return 0;
1267 
1268 destroy_expkey_cache:
1269         cache_destroy_net(nn->svc_expkey_cache, net);
1270 unregister_export_cache:
1271         cache_unregister_net(nn->svc_export_cache, net);
1272 destroy_export_cache:
1273         cache_destroy_net(nn->svc_export_cache, net);
1274         return rv;
1275 }
1276 
1277 /*
1278  * Flush exports table - called when last nfsd thread is killed
1279  */
1280 void
1281 nfsd_export_flush(struct net *net)
1282 {
1283         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1284 
1285         cache_purge(nn->svc_expkey_cache);
1286         cache_purge(nn->svc_export_cache);
1287 }
1288 
1289 /*
1290  * Shutdown the exports module.
1291  */
1292 void
1293 nfsd_export_shutdown(struct net *net)
1294 {
1295         struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1296 
1297         dprintk("nfsd: shutting down export module (net: %x).\n", net->ns.inum);
1298 
1299         cache_unregister_net(nn->svc_expkey_cache, net);
1300         cache_unregister_net(nn->svc_export_cache, net);
1301         cache_destroy_net(nn->svc_expkey_cache, net);
1302         cache_destroy_net(nn->svc_export_cache, net);
1303         svcauth_unix_purge(net);
1304 
1305         dprintk("nfsd: export shutdown complete (net: %x).\n", net->ns.inum);
1306 }

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