]> err.no Git - linux-2.6/blobdiff - fs/nfs/super.c
NFS: eliminate NIPQUAD(clp->cl_addr.sin_addr)
[linux-2.6] / fs / nfs / super.c
index 347c36341e53ebb2179e379104d50f2f9d666949..75f3cbf922a30a5b6c2b107fa0d0b27ba4535e8a 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/metrics.h>
 #include <linux/sunrpc/xprtsock.h>
+#include <linux/sunrpc/xprtrdma.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
@@ -68,7 +69,7 @@ enum {
        Opt_ac, Opt_noac,
        Opt_lock, Opt_nolock,
        Opt_v2, Opt_v3,
-       Opt_udp, Opt_tcp,
+       Opt_udp, Opt_tcp, Opt_rdma,
        Opt_acl, Opt_noacl,
        Opt_rdirplus, Opt_nordirplus,
        Opt_sharecache, Opt_nosharecache,
@@ -82,8 +83,8 @@ enum {
        Opt_actimeo,
        Opt_namelen,
        Opt_mountport,
-       Opt_mountprog, Opt_mountvers,
-       Opt_nfsprog, Opt_nfsvers,
+       Opt_mountvers,
+       Opt_nfsvers,
 
        /* Mount options that take string arguments */
        Opt_sec, Opt_proto, Opt_mountproto,
@@ -114,6 +115,7 @@ static match_table_t nfs_mount_option_tokens = {
        { Opt_v3, "v3" },
        { Opt_udp, "udp" },
        { Opt_tcp, "tcp" },
+       { Opt_rdma, "rdma" },
        { Opt_acl, "acl" },
        { Opt_noacl, "noacl" },
        { Opt_rdirplus, "rdirplus" },
@@ -135,9 +137,7 @@ static match_table_t nfs_mount_option_tokens = {
        { Opt_userspace, "retry=%u" },
        { Opt_namelen, "namlen=%u" },
        { Opt_mountport, "mountport=%u" },
-       { Opt_mountprog, "mountprog=%u" },
        { Opt_mountvers, "mountvers=%u" },
-       { Opt_nfsprog, "nfsprog=%u" },
        { Opt_nfsvers, "nfsvers=%u" },
        { Opt_nfsvers, "vers=%u" },
 
@@ -153,7 +153,7 @@ static match_table_t nfs_mount_option_tokens = {
 };
 
 enum {
-       Opt_xprt_udp, Opt_xprt_tcp,
+       Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma,
 
        Opt_xprt_err
 };
@@ -161,6 +161,7 @@ enum {
 static match_table_t nfs_xprt_protocol_tokens = {
        { Opt_xprt_udp, "udp" },
        { Opt_xprt_tcp, "tcp" },
+       { Opt_xprt_rdma, "rdma" },
 
        { Opt_xprt_err, NULL }
 };
@@ -199,6 +200,7 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru
 static int nfs_xdev_get_sb(struct file_system_type *fs_type,
                int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
 static void nfs_kill_super(struct super_block *);
+static void nfs_put_super(struct super_block *);
 
 static struct file_system_type nfs_fs_type = {
        .owner          = THIS_MODULE,
@@ -220,6 +222,7 @@ static const struct super_operations nfs_sops = {
        .alloc_inode    = nfs_alloc_inode,
        .destroy_inode  = nfs_destroy_inode,
        .write_inode    = nfs_write_inode,
+       .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
        .clear_inode    = nfs_clear_inode,
        .umount_begin   = nfs_umount_begin,
@@ -322,6 +325,28 @@ void __exit unregister_nfs_fs(void)
        unregister_filesystem(&nfs_fs_type);
 }
 
+void nfs_sb_active(struct nfs_server *server)
+{
+       atomic_inc(&server->active);
+}
+
+void nfs_sb_deactive(struct nfs_server *server)
+{
+       if (atomic_dec_and_test(&server->active))
+               wake_up(&server->active_wq);
+}
+
+static void nfs_put_super(struct super_block *sb)
+{
+       struct nfs_server *server = NFS_SB(sb);
+       /*
+        * Make sure there are no outstanding ops to this server.
+        * If so, wait for them to finish before allowing the
+        * unmount to continue.
+        */
+       wait_event(server->active_wq, atomic_read(&server->active) == 0);
+}
+
 /*
  * Deliver file system statistics to userspace
  */
@@ -421,7 +446,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                const char *nostr;
        } nfs_info[] = {
                { NFS_MOUNT_SOFT, ",soft", ",hard" },
-               { NFS_MOUNT_INTR, ",intr", "" },
+               { NFS_MOUNT_INTR, ",intr", ",nointr" },
                { NFS_MOUNT_NOCTO, ",nocto", "" },
                { NFS_MOUNT_NOAC, ",noac", "" },
                { NFS_MOUNT_NONLM, ",nolock", "" },
@@ -466,8 +491,9 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
 
        nfs_show_mount_options(m, nfss, 0);
 
-       seq_printf(m, ",addr="NIPQUAD_FMT,
-               NIPQUAD(nfss->nfs_client->cl_addr.sin_addr));
+       seq_printf(m, ",addr=%s",
+                       rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
+                                                       RPC_DISPLAY_ADDR));
 
        return 0;
 }
@@ -504,7 +530,7 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
        seq_printf(m, ",namelen=%d", nfss->namelen);
 
 #ifdef CONFIG_NFS_V4
-       if (nfss->nfs_client->cl_nfsversion == 4) {
+       if (nfss->nfs_client->rpc_ops->version == 4) {
                seq_printf(m, "\n\tnfsv4:\t");
                seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
                seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
@@ -668,6 +694,12 @@ static int nfs_parse_mount_options(char *raw,
                        mnt->timeo = 600;
                        mnt->retrans = 2;
                        break;
+               case Opt_rdma:
+                       mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
+                       mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                       mnt->timeo = 600;
+                       mnt->retrans = 2;
+                       break;
                case Opt_acl:
                        mnt->flags &= ~NFS_MOUNT_NOACL;
                        break;
@@ -754,13 +786,6 @@ static int nfs_parse_mount_options(char *raw,
                                return 0;
                        mnt->mount_server.port = option;
                        break;
-               case Opt_mountprog:
-                       if (match_int(args, &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       mnt->mount_server.program = option;
-                       break;
                case Opt_mountvers:
                        if (match_int(args, &option))
                                return 0;
@@ -768,13 +793,6 @@ static int nfs_parse_mount_options(char *raw,
                                return 0;
                        mnt->mount_server.version = option;
                        break;
-               case Opt_nfsprog:
-                       if (match_int(args, &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       mnt->nfs_server.program = option;
-                       break;
                case Opt_nfsvers:
                        if (match_int(args, &option))
                                return 0;
@@ -883,6 +901,13 @@ static int nfs_parse_mount_options(char *raw,
                                mnt->timeo = 600;
                                mnt->retrans = 2;
                                break;
+                       case Opt_xprt_rdma:
+                               /* vector side protocols to TCP */
+                               mnt->flags |= NFS_MOUNT_TCP;
+                               mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                               mnt->timeo = 600;
+                               mnt->retrans = 2;
+                               break;
                        default:
                                goto out_unrec_xprt;
                        }
@@ -902,6 +927,7 @@ static int nfs_parse_mount_options(char *raw,
                        case Opt_xprt_tcp:
                                mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
                                break;
+                       case Opt_xprt_rdma: /* not used for side protocols */
                        default:
                                goto out_unrec_xprt;
                        }
@@ -1026,9 +1052,6 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
  *
  * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
  *   mountproto=tcp after mountproto=udp, and so on
- *
- * XXX: as far as I can tell, changing the NFS program number is not
- *      supported in the NFS client.
  */
 static int nfs_validate_mount_data(void *options,
                                   struct nfs_parsed_mount_data *args,
@@ -1037,10 +1060,11 @@ static int nfs_validate_mount_data(void *options,
 {
        struct nfs_mount_data *data = (struct nfs_mount_data *)options;
 
+       memset(args, 0, sizeof(*args));
+
        if (data == NULL)
                goto out_no_data;
 
-       memset(args, 0, sizeof(*args));
        args->flags             = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP);
        args->rsize             = NFS_MAX_FILE_IO_SIZE;
        args->wsize             = NFS_MAX_FILE_IO_SIZE;
@@ -1051,9 +1075,7 @@ static int nfs_validate_mount_data(void *options,
        args->acdirmin          = 30;
        args->acdirmax          = 60;
        args->mount_server.protocol = XPRT_TRANSPORT_UDP;
-       args->mount_server.program = NFS_MNT_PROGRAM;
        args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-       args->nfs_server.program = NFS_PROGRAM;
 
        switch (data->version) {
        case 1:
@@ -1083,6 +1105,10 @@ static int nfs_validate_mount_data(void *options,
                if (mntfh->size < sizeof(mntfh->data))
                        memset(mntfh->data + mntfh->size, 0,
                               sizeof(mntfh->data) - mntfh->size);
+
+               if (!nfs_verify_server_address((struct sockaddr *) &data->addr))
+                       goto out_no_address;
+
                /*
                 * Translate to nfs_parsed_mount_data, which nfs_fill_super
                 * can deal with.
@@ -1114,6 +1140,10 @@ static int nfs_validate_mount_data(void *options,
                if (nfs_parse_mount_options((char *)options, args) == 0)
                        return -EINVAL;
 
+               if (!nfs_verify_server_address((struct sockaddr *)
+                                               &args->nfs_server.address))
+                       goto out_no_address;
+
                c = strchr(dev_name, ':');
                if (c == NULL)
                        return -EINVAL;
@@ -1142,10 +1172,6 @@ static int nfs_validate_mount_data(void *options,
                goto out_v3_not_compiled;
 #endif /* !CONFIG_NFS_V3 */
 
-       if (!nfs_verify_server_address((struct sockaddr *)
-                                               &args->nfs_server.address))
-               goto out_no_address;
-
        return 0;
 
 out_no_data:
@@ -1453,6 +1479,11 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
                error = PTR_ERR(mntroot);
                goto error_splat_super;
        }
+       if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
+               dput(mntroot);
+               error = -ESTALE;
+               goto error_splat_super;
+       }
 
        s->s_flags |= MS_ACTIVE;
        mnt->mnt_sb = s;
@@ -1510,10 +1541,11 @@ static int nfs4_validate_mount_data(void *options,
        struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
        char *c;
 
+       memset(args, 0, sizeof(*args));
+
        if (data == NULL)
                goto out_no_data;
 
-       memset(args, 0, sizeof(*args));
        args->rsize             = NFS_MAX_FILE_IO_SIZE;
        args->wsize             = NFS_MAX_FILE_IO_SIZE;
        args->timeo             = 600;
@@ -1591,6 +1623,8 @@ static int nfs4_validate_mount_data(void *options,
                if (nfs_parse_mount_options((char *)options, args) == 0)
                        return -EINVAL;
 
+               if (args->nfs_server.address.sin_port == 0)
+                       args->nfs_server.address.sin_port = htons(NFS_PORT);
                if (!nfs_verify_server_address((struct sockaddr *)
                                                &args->nfs_server.address))
                        return -EINVAL;
@@ -1615,21 +1649,16 @@ static int nfs4_validate_mount_data(void *options,
                len = c - dev_name;
                if (len > NFS4_MAXNAMLEN)
                        return -ENAMETOOLONG;
-               args->nfs_server.hostname = kzalloc(len, GFP_KERNEL);
-               if (args->nfs_server.hostname == NULL)
-                       return -ENOMEM;
-               strncpy(args->nfs_server.hostname, dev_name, len - 1);
+               /* N.B. caller will free nfs_server.hostname in all cases */
+               args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
 
                c++;                    /* step over the ':' */
                len = strlen(c);
                if (len > NFS4_MAXPATHLEN)
                        return -ENAMETOOLONG;
-               args->nfs_server.export_path = kzalloc(len + 1, GFP_KERNEL);
-               if (args->nfs_server.export_path == NULL)
-                       return -ENOMEM;
-               strncpy(args->nfs_server.export_path, c, len);
+               args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL);
 
-               dprintk("MNTPATH: %s\n", args->nfs_server.export_path);
+               dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path);
 
                if (args->client_address == NULL)
                        goto out_no_client_address;
@@ -1798,6 +1827,11 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
                error = PTR_ERR(mntroot);
                goto error_splat_super;
        }
+       if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
+               dput(mntroot);
+               error = -ESTALE;
+               goto error_splat_super;
+       }
 
        s->s_flags |= MS_ACTIVE;
        mnt->mnt_sb = s;
@@ -1872,6 +1906,11 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
                error = PTR_ERR(mntroot);
                goto error_splat_super;
        }
+       if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
+               dput(mntroot);
+               error = -ESTALE;
+               goto error_splat_super;
+       }
 
        s->s_flags |= MS_ACTIVE;
        mnt->mnt_sb = s;