CTC++ Coverage Report - Execution Profile    #994/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: fs/nfsd/export.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 3/722)

Start/ End/    
True False - Line Source

  1 #define MSNFS   /* HACK HACK */
  2 /*
  3  * linux/fs/nfsd/export.c
  4  *
  5  * NFS exporting and validation.
  6  *
  7  * We maintain a list of clients, each of which has a list of
  8  * exports. To export an fs to a given client, you first have
  9  * to create the client entry with NFSCTL_ADDCLIENT, which
  10  * creates a client control block and adds it to the hash
  11  * table. Then, you call NFSCTL_EXPORT for each fs.
  12  *
  13  *
  14  * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
  15  */
  16 
  17 #include <linux/unistd.h>
  18 #include <linux/slab.h>
  19 #include <linux/sched.h>
  20 #include <linux/stat.h>
  21 #include <linux/in.h>
  22 #include <linux/seq_file.h>
  23 #include <linux/syscalls.h>
  24 #include <linux/rwsem.h>
  25 #include <linux/dcache.h>
  26 #include <linux/namei.h>
  27 #include <linux/mount.h>
  28 #include <linux/hash.h>
  29 #include <linux/module.h>
  30 
  31 #include <linux/sunrpc/svc.h>
  32 #include <linux/nfsd/nfsd.h>
  33 #include <linux/nfsd/nfsfh.h>
  34 #include <linux/nfsd/syscall.h>
  35 #include <linux/lockd/bind.h>
  36 
  37 #define NFSDDBG_FACILITY   NFSDDBG_EXPORT
  38 #define NFSD_PARANOIA 1
  39 
  40 typedef struct auth_domain   svc_client;
  41 typedef struct svc_export   svc_export;
  42 
  43 static void      exp_do_unexport(svc_export *unexp);
  44 static int      exp_verify_string(char *cp, int max);
  45 
  46 /*
  47  * We have two caches.
  48  * One maps client+vfsmnt+dentry to export options - the export map
  49  * The other maps client+filehandle-fragment to export options. - the expkey map
  50  *
  51  * The export options are actually stored in the first map, and the
  52  * second map contains a reference to the entry in the first map.
  53  */
  54 
  55 #define   EXPKEY_HASHBITS      8
  56 #define   EXPKEY_HASHMAX      (1 << EXPKEY_HASHBITS)
  57 #define   EXPKEY_HASHMASK      (EXPKEY_HASHMAX -1)
  58 static struct cache_head *expkey_table[EXPKEY_HASHMAX];
  59 
 
- 60 static inline int svc_expkey_hash(struct svc_expkey *item)
  61 {
  62    int hash = item->ek_fsidtype;
  63    char * cp = (char*)item->ek_fsid;
  64    int len = key_len(item->ek_fsidtype);
  65 
  66    hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
  67    hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
 - 68    return hash & EXPKEY_HASHMASK;
  69 }
  70 
 
- 71 void expkey_put(struct cache_head *item, struct cache_detail *cd)
  72 {
- 73    if (cache_put(item, cd)) {
  74       struct svc_expkey *key = container_of(item, struct svc_expkey, h);
  75       if (test_bit(CACHE_VALID, &item->flags) &&
- 76           !test_bit(CACHE_NEGATIVE, &item->flags))
 - 76     (T) && !(F)
 - 76     (T) && !(T)
 - 76     (F) && !(_)
- 76   ternary-?: __builtin_constant_p ( 0 )
- 76   ternary-?: __builtin_constant_p ( 1 )
  77          exp_put(key->ek_export);
  78       auth_domain_put(key->ek_client);
  79       kfree(key);
  80    }
  81 }
  82 
 
- 83 static void expkey_request(struct cache_detail *cd,
  84             struct cache_head *h,
  85             char **bpp, int *blen)
  86 {
  87    /* client fsidtype \xfsid */
  88    struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
  89    char type[5];
  90 
  91    qword_add(bpp, blen, ek->ek_client->name);
  92    snprintf(type, 5, "%d", ek->ek_fsidtype);
  93    qword_add(bpp, blen, type);
  94    qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
  95    (*bpp)[-1] = '\n';
  96 }
  97 
  98 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
 
- 99 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
  100 {
  101    /* client fsidtype fsid [path] */
  102    char *buf;
  103    int len;
  104    struct auth_domain *dom = NULL;
  105    int err;
  106    int fsidtype;
  107    char *ep;
  108    struct svc_expkey key;
  109 
- 110    if (mesg[mlen-1] != '\n')
 - 111       return -EINVAL;
  112    mesg[mlen-1] = 0;
  113 
  114    buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  115    err = -ENOMEM;
- 116    if (!buf) goto out;
 - 116   goto out
  117 
  118    err = -EINVAL;
- 119    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 - 120       goto out;
  121 
  122    err = -ENOENT;
  123    dom = auth_domain_find(buf);
- 124    if (!dom)
 - 125       goto out;
    126    dprintk("found domain %s\n", buf);
- 126   if (nfsd_debug & 0x0004)
- 126 do-while (0)
  127 
  128    err = -EINVAL;
- 129    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 - 130       goto out;
  131    fsidtype = simple_strtoul(buf, &ep, 10);
- 132    if (*ep)
 - 133       goto out;
    134    dprintk("found fsidtype %d\n", fsidtype);
- 134   if (nfsd_debug & 0x0004)
- 134 do-while (0)
- 135    if (fsidtype > 2)
 - 136       goto out;
- 137    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 - 138       goto out;
    139    dprintk("found fsid length %d\n", len);
- 139   if (nfsd_debug & 0x0004)
- 139 do-while (0)
- 140    if (len != key_len(fsidtype))
 - 141       goto out;
  142 
  143    /* OK, we seem to have a valid key */
  144    key.h.flags = 0;
  145    key.h.expiry_time = get_expiry(&mesg);
- 146    if (key.h.expiry_time == 0)
 - 147       goto out;
  148 
  149    key.ek_client = dom;   
  150    key.ek_fsidtype = fsidtype;
  151    memcpy(key.ek_fsid, buf, len);
  152 
  153    /* now we want a pathname, or empty meaning NEGATIVE  */
- 154    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
 - 155       goto out;
    156    dprintk("Path seems to be <%s>\n", buf);
- 156   if (nfsd_debug & 0x0004)
- 156 do-while (0)
  157    err = 0;
- 158    if (len == 0) {
  159       struct svc_expkey *ek;
  160       set_bit(CACHE_NEGATIVE, &key.h.flags);
  161       ek = svc_expkey_lookup(&key, 1);
- 162       if (ek)
  163          expkey_put(&ek->h, &svc_expkey_cache);
    164    } else {
  165       struct nameidata nd;
  166       struct svc_expkey *ek;
  167       struct svc_export *exp;
  168       err = path_lookup(buf, 0, &nd);
- 169       if (err)
 - 170          goto out;
  171 
    172       dprintk("Found the path %s\n", buf);
- 172     if (nfsd_debug & 0x0004)
- 172   do-while (0)
  173       exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
  174 
  175       err = -ENOENT;
- 176       if (!exp)
 - 177          goto out_nd;
  178       key.ek_export = exp;
    179       dprintk("And found export\n");
- 179     if (nfsd_debug & 0x0004)
- 179   do-while (0)
  180       
  181       ek = svc_expkey_lookup(&key, 1);
- 182       if (ek)
  183          expkey_put(&ek->h, &svc_expkey_cache);
  184       exp_put(exp);
  185       err = 0;
  186    out_nd:
  187       path_release(&nd);
  188    }
  189    cache_flush();
  190  out:
- 191    if (dom)
  192       auth_domain_put(dom);
  193    kfree(buf);
 - 194    return err;
  195 }
  196 
 
- 197 static int expkey_show(struct seq_file *m,
  198              struct cache_detail *cd,
  199              struct cache_head *h)
  200 {
  201    struct svc_expkey *ek ;
  202 
- 203    if (h ==NULL) {
  204       seq_puts(m, "#domain fsidtype fsid [path]\n");
 - 205       return 0;
  206    }
  207    ek = container_of(h, struct svc_expkey, h);
  208    seq_printf(m, "%s %d 0x%08x", ek->ek_client->name,
  209          ek->ek_fsidtype, ek->ek_fsid[0]);
- 210    if (ek->ek_fsidtype != 1)
  211       seq_printf(m, "%08x", ek->ek_fsid[1]);
- 212    if (ek->ek_fsidtype == 2)
  213       seq_printf(m, "%08x", ek->ek_fsid[2]);
  214    if (test_bit(CACHE_VALID, &h->flags) && 
- 215        !test_bit(CACHE_NEGATIVE, &h->flags)) {
 - 215   (T) && !(F)
 - 215   (T) && !(T)
 - 215   (F) && !(_)
- 215 ternary-?: __builtin_constant_p ( 0 )
- 215 ternary-?: __builtin_constant_p ( 1 )
  216       seq_printf(m, " ");
  217       seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n");
  218    }
  219    seq_printf(m, "\n");
 - 220    return 0;
  221 }
  222    
  223 struct cache_detail svc_expkey_cache = {
  224    .owner      = THIS_MODULE,
  225    .hash_size   = EXPKEY_HASHMAX,
  226    .hash_table   = expkey_table,
  227    .name      = "nfsd.fh",
  228    .cache_put   = expkey_put,
  229    .cache_request   = expkey_request,
  230    .cache_parse   = expkey_parse,
  231    .cache_show   = expkey_show,
  232 };
  233 
 
- 234 static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
  235 {
  236    if (a->ek_fsidtype != b->ek_fsidtype ||
  237        a->ek_client != b->ek_client ||
- 238        memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0)
 - 238   T || _ || _
 - 238   F || T || _
 - 238   F || F || T
 - 238   F || F || F
 - 239       return 0;
 - 240    return 1;
  241 }
  242 
 
- 243 static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
  244 {
  245    cache_get(&item->ek_client->h);
  246    new->ek_client = item->ek_client;
  247    new->ek_fsidtype = item->ek_fsidtype;
  248    new->ek_fsid[0] = item->ek_fsid[0];
  249    new->ek_fsid[1] = item->ek_fsid[1];
  250    new->ek_fsid[2] = item->ek_fsid[2];
  251 }
  252 
 
- 253 static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
  254 {
  255    cache_get(&item->ek_export->h);
  256    new->ek_export = item->ek_export;
  257 }
  258 
 
- 259 static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
- 259 if (set || new)
 - 259   T || _
 - 259   F || T
 - 259   F || F
    259   do
    259     do
- 259     do-while (0)
- 259   do-while (0)
    259 else
    259   do
    259     do
- 259     do-while (0)
- 259   do-while (0)
- 259 for (;* hp != ( ( void * ) 0 );)
- 259   if (svc_expkey_match ( item , tmp ))
- 259     if (set && ! 0 && ( __builtin_constant_p (..
 - 259       T && T && (T) && T
 - 259       T && T && (T) && F
 - 259       T && T && (F) && _
 - 259       T && F && (_) && _
 - 259       F && _ && (_) && _
- 259     ternary-?: __builtin_constant_p ( 0 )
 - 259       break
- 259     if (new)
- 259     if (set)
- 259       if (! 0 && ( __builtin_constant_p ( 0 ) ..
 - 259         T && (T)
 - 259         T && (F)
 - 259         F && (_)
- 259       ternary-?: __builtin_constant_p ( 0 )
- 259       if (( __builtin_constant_p ( 1 ) ? const..
- 259       ternary-?: __builtin_constant_p ( 1 )
    259       else
- 259     if (set || new)
 - 259       T || _
 - 259       F || T
 - 259       F || F
    259       do
    259         do
- 259         do-while (0)
- 259       do-while (0)
    259     else
    259       do
    259         do
- 259         do-while (0)
- 259       do-while (0)
- 259     if (set)
- 259     if (set && ! 0 && new)
 - 259       T && T && T
 - 259       T && T && F
 - 259       T && F && _
 - 259       F && _ && _
- 259     if (new)
 - 259     return tmp
- 259 if (new)
- 259   if (set)
- 259     if (( __builtin_constant_p ( 1 ) ? constan..
- 259     ternary-?: __builtin_constant_p ( 1 )
    259     else
- 259 if (set || new)
 - 259   T || _
 - 259   F || T
 - 259   F || F
    259   do
    259     do
- 259     do-while (0)
- 259   do-while (0)
    259 else
    259   do
    259     do
- 259     do-while (0)
- 259   do-while (0)
- 259 if (new && set)
 - 259   T && T
 - 259   T && F
 - 259   F && _
- 259 if (new)
 - 259   return new
- 259 if (new)
 - 259   goto retry
 - 259 return ( ( void * ) 0 )
  260 
  261 #define   EXPORT_HASHBITS      8
  262 #define   EXPORT_HASHMAX      (1<< EXPORT_HASHBITS)
  263 #define   EXPORT_HASHMASK      (EXPORT_HASHMAX -1)
  264 
  265 static struct cache_head *export_table[EXPORT_HASHMAX];
  266 
 
- 267 static inline int svc_export_hash(struct svc_export *item)
  268 {
  269    int rv;
  270 
  271    rv = hash_ptr(item->ex_client, EXPORT_HASHBITS);
  272    rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS);
  273    rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS);
 - 274    return rv;
  275 }
  276 
 
- 277 void svc_export_put(struct cache_head *item, struct cache_detail *cd)
  278 {
- 279    if (cache_put(item, cd)) {
  280       struct svc_export *exp = container_of(item, struct svc_export, h);
  281       dput(exp->ex_dentry);
  282       mntput(exp->ex_mnt);
  283       auth_domain_put(exp->ex_client);
  284       kfree(exp);
  285    }
  286 }
  287 
 
- 288 static void svc_export_request(struct cache_detail *cd,
  289                 struct cache_head *h,
  290                 char **bpp, int *blen)
  291 {
  292    /*  client path */
  293    struct svc_export *exp = container_of(h, struct svc_export, h);
  294    char *pth;
  295 
  296    qword_add(bpp, blen, exp->ex_client->name);
  297    pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen);
- 298    if (IS_ERR(pth)) {
  299       /* is this correct? */
  300       (*bpp)[0] = '\n';
 - 301       return;
  302    }
  303    qword_add(bpp, blen, pth);
  304    (*bpp)[-1] = '\n';
  305 }
  306 
  307 static struct svc_export *svc_export_lookup(struct svc_export *, int);
  308 
 
- 309 static int check_export(struct inode *inode, int flags)
  310 {
  311 
  312    /* We currently export only dirs and regular files.
  313     * This is what umountd does.
  314     */
  315    if (!S_ISDIR(inode->i_mode) &&
- 316        !S_ISREG(inode->i_mode))
 - 316   !(F) && !(F)
 - 316   !(T) && !(_)
 - 316   !(F) && !(T)
 - 317       return -ENOTDIR;
  318 
  319    /* There are two requirements on a filesystem to be exportable.
  320     * 1:  We must be able to identify the filesystem from a number.
  321     *       either a device number (so FS_REQUIRES_DEV needed)
  322     *       or an FSID number (so NFSEXP_FSID needed).
  323     * 2:  We must be able to find an inode from a filehandle.
  324     *       This means that s_export_op must be set.
  325     */
  326    if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
- 327        !(flags & NFSEXP_FSID)) {
 - 327   !(F) && !(F)
 - 327   !(T) && !(_)
 - 327   !(F) && !(T)
    328       dprintk("exp_export: export of non-dev fs without fsid");
- 328     if (nfsd_debug & 0x0004)
- 328   do-while (0)
 - 329       return -EINVAL;
  330    }
- 331    if (!inode->i_sb->s_export_op) {
    332       dprintk("exp_export: export of invalid fs type.\n");
- 332     if (nfsd_debug & 0x0004)
- 332   do-while (0)
 - 333       return -EINVAL;
  334    }
  335 
  336    /* Ok, we can export it */;
- 337    if (!inode->i_sb->s_export_op->find_exported_dentry)
  338       inode->i_sb->s_export_op->find_exported_dentry =
  339          find_exported_dentry;
 - 340    return 0;
  341 
  342 }
  343 
 
- 344 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
  345 {
  346    /* client path expiry [flags anonuid anongid fsid] */
  347    char *buf;
  348    int len;
  349    int err;
  350    struct auth_domain *dom = NULL;
  351    struct nameidata nd;
  352    struct svc_export exp, *expp;
  353    int an_int;
  354 
  355    nd.dentry = NULL;
  356 
- 357    if (mesg[mlen-1] != '\n')
 - 358       return -EINVAL;
  359    mesg[mlen-1] = 0;
  360 
  361    buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  362    err = -ENOMEM;
- 363    if (!buf) goto out;
 - 363   goto out
  364 
  365    /* client */
  366    len = qword_get(&mesg, buf, PAGE_SIZE);
  367    err = -EINVAL;
- 368    if (len <= 0) goto out;
 - 368   goto out
  369 
  370    err = -ENOENT;
  371    dom = auth_domain_find(buf);
- 372    if (!dom)
 - 373       goto out;
  374 
  375    /* path */
  376    err = -EINVAL;
- 377    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 - 378       goto out;
  379