nfsd: Drop reference in expkey_parse error cases
[firefly-linux-kernel-4.4.55.git] / fs / nfsd / export.c
index 7d7896814fa40cbc7e1c98cb407d3022a419723f..7ce2c6e4e23ee11c5b2cfc0a2b056dbf6d57e6a1 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
 
 #define NFSDDBG_FACILITY       NFSDDBG_EXPORT
 
@@ -63,10 +64,8 @@ static void expkey_put(struct kref *ref)
        struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
 
        if (test_bit(CACHE_VALID, &key->h.flags) &&
-           !test_bit(CACHE_NEGATIVE, &key->h.flags)) {
-               dput(key->ek_dentry);
-               mntput(key->ek_mnt);
-       }
+           !test_bit(CACHE_NEGATIVE, &key->h.flags))
+               path_put(&key->ek_path);
        auth_domain_put(key->ek_client);
        kfree(key);
 }
@@ -152,8 +151,10 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
 
        /* now we want a pathname, or empty meaning NEGATIVE  */
        err = -EINVAL;
-       if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
+       if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) {
+               cache_put(&ek->h, &svc_expkey_cache);
                goto out;
+       }
        dprintk("Path seems to be <%s>\n", buf);
        err = 0;
        if (len == 0) {
@@ -165,13 +166,14 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
        } else {
                struct nameidata nd;
                err = path_lookup(buf, 0, &nd);
-               if (err)
+               if (err) {
+                       cache_put(&ek->h, &svc_expkey_cache);
                        goto out;
+               }
 
                dprintk("Found the path %s\n", buf);
-               key.ek_mnt = nd.path.mnt;
-               key.ek_dentry = nd.path.dentry;
-               
+               key.ek_path = nd.path;
+
                ek = svc_expkey_update(&key, ek);
                if (ek)
                        cache_put(&ek->h, &svc_expkey_cache);
@@ -206,7 +208,7 @@ static int expkey_show(struct seq_file *m,
        if (test_bit(CACHE_VALID, &h->flags) && 
            !test_bit(CACHE_NEGATIVE, &h->flags)) {
                seq_printf(m, " ");
-               seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n");
+               seq_path(m, &ek->ek_path, "\\ \t\n");
        }
        seq_printf(m, "\n");
        return 0;
@@ -243,8 +245,8 @@ static inline void expkey_update(struct cache_head *cnew,
        struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
        struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 
-       new->ek_mnt = mntget(item->ek_mnt);
-       new->ek_dentry = dget(item->ek_dentry);
+       new->ek_path = item->ek_path;
+       path_get(&item->ek_path);
 }
 
 static struct cache_head *expkey_alloc(void)
@@ -348,7 +350,7 @@ static void svc_export_request(struct cache_detail *cd,
        char *pth;
 
        qword_add(bpp, blen, exp->ex_client->name);
-       pth = d_path(exp->ex_path.dentry, exp->ex_path.mnt, *bpp, *blen);
+       pth = d_path(&exp->ex_path, *bpp, *blen);
        if (IS_ERR(pth)) {
                /* is this correct? */
                (*bpp)[0] = '\n';
@@ -652,7 +654,7 @@ static int svc_export_show(struct seq_file *m,
                return 0;
        }
        exp = container_of(h, struct svc_export, h);
-       seq_path(m, exp->ex_path.mnt, exp->ex_path.dentry, " \t\n\\");
+       seq_path(m, &exp->ex_path, " \t\n\\");
        seq_putc(m, '\t');
        seq_escape(m, exp->ex_client->name, " \t\n\\");
        seq_putc(m, '(');
@@ -814,8 +816,7 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
        key.ek_client = clp;
        key.ek_fsidtype = fsid_type;
        memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
-       key.ek_mnt = exp->ex_path.mnt;
-       key.ek_dentry = exp->ex_path.dentry;
+       key.ek_path = exp->ex_path;
        key.h.expiry_time = NEVER;
        key.h.flags = 0;
 
@@ -864,7 +865,7 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt,
 {
        struct svc_export *exp, key;
        int err;
-       
+
        if (!clp)
                return ERR_PTR(-ENOENT);
 
@@ -1026,7 +1027,7 @@ exp_export(struct nfsctl_export *nxp)
        /* Look up the dentry */
        err = path_lookup(nxp->ex_path, 0, &nd);
        if (err)
-               goto out_unlock;
+               goto out_put_clp;
        err = -EINVAL;
 
        exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL);
@@ -1036,9 +1037,9 @@ exp_export(struct nfsctl_export *nxp)
        /* must make sure there won't be an ex_fsid clash */
        if ((nxp->ex_flags & NFSEXP_FSID) &&
            (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
-           fsid_key->ek_mnt &&
-           (fsid_key->ek_mnt != nd.path.mnt ||
-            fsid_key->ek_dentry != nd.path.dentry))
+           fsid_key->ek_path.mnt &&
+           (fsid_key->ek_path.mnt != nd.path.mnt ||
+            fsid_key->ek_path.dentry != nd.path.dentry))
                goto finish;
 
        if (!IS_ERR(exp)) {
@@ -1093,9 +1094,9 @@ finish:
                exp_put(exp);
        if (fsid_key && !IS_ERR(fsid_key))
                cache_put(&fsid_key->h, &svc_expkey_cache);
-       if (clp)
-               auth_domain_put(clp);
        path_put(&nd.path);
+out_put_clp:
+       auth_domain_put(clp);
 out_unlock:
        exp_writeunlock();
 out:
@@ -1218,7 +1219,7 @@ static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
        if (IS_ERR(ek))
                return ERR_CAST(ek);
 
-       exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
+       exp = exp_get_by_name(clp, ek->ek_path.mnt, ek->ek_path.dentry, reqp);
        cache_put(&ek->h, &svc_expkey_cache);
 
        if (IS_ERR(exp))
@@ -1552,6 +1553,7 @@ exp_addclient(struct nfsctl_client *ncp)
 {
        struct auth_domain      *dom;
        int                     i, err;
+       struct in6_addr addr6;
 
        /* First, consistency check. */
        err = -EINVAL;
@@ -1570,9 +1572,10 @@ exp_addclient(struct nfsctl_client *ncp)
                goto out_unlock;
 
        /* Insert client into hashtable. */
-       for (i = 0; i < ncp->cl_naddr; i++)
-               auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+       for (i = 0; i < ncp->cl_naddr; i++) {
+               ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
+               auth_unix_add_addr(&addr6, dom);
+       }
        auth_unix_forget_old(dom);
        auth_domain_put(dom);