Merge commit 'v2.6.30' into for-2.6.31
[safe/jmp/linux-2.6] / fs / nfs / super.c
index 8b28b95..d2d6778 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  nfs superblock handling functions
  *
- *  Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
+ *  Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some
  *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
  *
  *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
@@ -60,6 +60,7 @@
 #include "delegation.h"
 #include "iostat.h"
 #include "internal.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -75,6 +76,8 @@ enum {
        Opt_acl, Opt_noacl,
        Opt_rdirplus, Opt_nordirplus,
        Opt_sharecache, Opt_nosharecache,
+       Opt_resvport, Opt_noresvport,
+       Opt_fscache, Opt_nofscache,
 
        /* Mount options that take integer arguments */
        Opt_port,
@@ -92,6 +95,7 @@ enum {
        Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
        Opt_addr, Opt_mountaddr, Opt_clientaddr,
        Opt_lookupcache,
+       Opt_fscache_uniq,
 
        /* Special mount options */
        Opt_userspace, Opt_deprecated, Opt_sloppy,
@@ -129,6 +133,11 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_nordirplus, "nordirplus" },
        { Opt_sharecache, "sharecache" },
        { Opt_nosharecache, "nosharecache" },
+       { Opt_resvport, "resvport" },
+       { Opt_noresvport, "noresvport" },
+       { Opt_fscache, "fsc" },
+       { Opt_fscache_uniq, "fsc=%s" },
+       { Opt_nofscache, "nofsc" },
 
        { Opt_port, "port=%u" },
        { Opt_rsize, "rsize=%u" },
@@ -462,14 +471,12 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
        switch (sap->sa_family) {
        case AF_INET: {
                struct sockaddr_in *sin = (struct sockaddr_in *)sap;
-               seq_printf(m, ",mountaddr=" NIPQUAD_FMT,
-                               NIPQUAD(sin->sin_addr.s_addr));
+               seq_printf(m, ",mountaddr=%pI4", &sin->sin_addr.s_addr);
                break;
        }
        case AF_INET6: {
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
-               seq_printf(m, ",mountaddr=" NIP6_FMT,
-                               NIP6(sin6->sin6_addr));
+               seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr);
                break;
        }
        default:
@@ -514,7 +521,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                { NFS_MOUNT_NONLM, ",nolock", "" },
                { NFS_MOUNT_NOACL, ",noacl", "" },
                { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
-               { NFS_MOUNT_UNSHARED, ",nosharecache", ""},
+               { NFS_MOUNT_UNSHARED, ",nosharecache", "" },
+               { NFS_MOUNT_NORESVPORT, ",noresvport", "" },
                { 0, NULL, NULL }
        };
        const struct proc_nfs_info *nfs_infop;
@@ -561,6 +569,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        if (clp->rpc_ops->version == 4)
                seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
 #endif
+       if (nfss->options & NFS_OPTION_FSCACHE)
+               seq_printf(m, ",fsc");
 }
 
 /*
@@ -639,6 +649,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
                        totals.events[i] += stats->events[i];
                for (i = 0; i < __NFSIOS_BYTESMAX; i++)
                        totals.bytes[i] += stats->bytes[i];
+#ifdef CONFIG_NFS_FSCACHE
+               for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
+                       totals.fscache[i] += stats->fscache[i];
+#endif
 
                preempt_enable();
        }
@@ -649,6 +663,13 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
        seq_printf(m, "\n\tbytes:\t");
        for (i = 0; i < __NFSIOS_BYTESMAX; i++)
                seq_printf(m, "%Lu ", totals.bytes[i]);
+#ifdef CONFIG_NFS_FSCACHE
+       if (nfss->options & NFS_OPTION_FSCACHE) {
+               seq_printf(m, "\n\tfsc:\t");
+               for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
+                       seq_printf(m, "%Lu ", totals.bytes[i]);
+       }
+#endif
        seq_printf(m, "\n");
 
        rpc_print_iostats(m, nfss->client);
@@ -662,9 +683,12 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
  */
 static void nfs_umount_begin(struct super_block *sb)
 {
-       struct nfs_server *server = NFS_SB(sb);
+       struct nfs_server *server;
        struct rpc_clnt *rpc;
 
+       lock_kernel();
+
+       server = NFS_SB(sb);
        /* -EIO all pending I/O */
        rpc = server->client_acl;
        if (!IS_ERR(rpc))
@@ -672,6 +696,8 @@ static void nfs_umount_begin(struct super_block *sb)
        rpc = server->client;
        if (!IS_ERR(rpc))
                rpc_killall_tasks(rpc);
+
+       unlock_kernel();
 }
 
 /*
@@ -1016,6 +1042,7 @@ static int nfs_parse_mount_options(char *raw,
                case Opt_rdma:
                        mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
                        mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                       xprt_load_transport(p);
                        break;
                case Opt_acl:
                        mnt->flags &= ~NFS_MOUNT_NOACL;
@@ -1035,6 +1062,30 @@ static int nfs_parse_mount_options(char *raw,
                case Opt_nosharecache:
                        mnt->flags |= NFS_MOUNT_UNSHARED;
                        break;
+               case Opt_resvport:
+                       mnt->flags &= ~NFS_MOUNT_NORESVPORT;
+                       break;
+               case Opt_noresvport:
+                       mnt->flags |= NFS_MOUNT_NORESVPORT;
+                       break;
+               case Opt_fscache:
+                       mnt->options |= NFS_OPTION_FSCACHE;
+                       kfree(mnt->fscache_uniq);
+                       mnt->fscache_uniq = NULL;
+                       break;
+               case Opt_nofscache:
+                       mnt->options &= ~NFS_OPTION_FSCACHE;
+                       kfree(mnt->fscache_uniq);
+                       mnt->fscache_uniq = NULL;
+                       break;
+               case Opt_fscache_uniq:
+                       string = match_strdup(args);
+                       if (!string)
+                               goto out_nomem;
+                       kfree(mnt->fscache_uniq);
+                       mnt->fscache_uniq = string;
+                       mnt->options |= NFS_OPTION_FSCACHE;
+                       break;
 
                /*
                 * options that take numeric values
@@ -1182,7 +1233,6 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_nomem;
                        token = match_token(string,
                                            nfs_xprt_protocol_tokens, args);
-                       kfree(string);
 
                        switch (token) {
                        case Opt_xprt_udp:
@@ -1197,12 +1247,14 @@ static int nfs_parse_mount_options(char *raw,
                                /* vector side protocols to TCP */
                                mnt->flags |= NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+                               xprt_load_transport(string);
                                break;
                        default:
                                errors++;
                                dfprintk(MOUNT, "NFS:   unrecognized "
                                                "transport protocol\n");
                        }
+                       kfree(string);
                        break;
                case Opt_mountproto:
                        string = match_strdup(args);
@@ -1329,8 +1381,14 @@ out_security_failure:
 static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                         struct nfs_fh *root_fh)
 {
-       struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address;
-       char *hostname;
+       struct nfs_mount_request request = {
+               .sap            = (struct sockaddr *)
+                                               &args->mount_server.address,
+               .dirpath        = args->nfs_server.export_path,
+               .protocol       = args->mount_server.protocol,
+               .fh             = root_fh,
+               .noresvport     = args->flags & NFS_MOUNT_NORESVPORT,
+       };
        int status;
 
        if (args->mount_server.version == 0) {
@@ -1339,42 +1397,38 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                else
                        args->mount_server.version = NFS_MNT_VERSION;
        }
+       request.version = args->mount_server.version;
 
        if (args->mount_server.hostname)
-               hostname = args->mount_server.hostname;
+               request.hostname = args->mount_server.hostname;
        else
-               hostname = args->nfs_server.hostname;
+               request.hostname = args->nfs_server.hostname;
 
        /*
         * Construct the mount server's address.
         */
        if (args->mount_server.address.ss_family == AF_UNSPEC) {
-               memcpy(sap, &args->nfs_server.address,
+               memcpy(request.sap, &args->nfs_server.address,
                       args->nfs_server.addrlen);
                args->mount_server.addrlen = args->nfs_server.addrlen;
        }
+       request.salen = args->mount_server.addrlen;
 
        /*
         * autobind will be used if mount_server.port == 0
         */
-       nfs_set_port(sap, args->mount_server.port);
+       nfs_set_port(request.sap, args->mount_server.port);
 
        /*
         * Now ask the mount server to map our export path
         * to a file handle.
         */
-       status = nfs_mount(sap,
-                          args->mount_server.addrlen,
-                          hostname,
-                          args->nfs_server.export_path,
-                          args->mount_server.version,
-                          args->mount_server.protocol,
-                          root_fh);
+       status = nfs_mount(&request);
        if (status == 0)
                return 0;
 
        dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
-                       hostname, status);
+                       request.hostname, status);
        return status;
 }
 
@@ -1858,8 +1912,6 @@ static void nfs_clone_super(struct super_block *sb,
        nfs_initialise_sb(sb);
 }
 
-#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
-
 static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
 {
        const struct nfs_server *a = s->s_fs_info;
@@ -2024,6 +2076,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs_fill_super(s, data);
+               nfs_fscache_get_super_cookie(s, data);
        }
 
        mntroot = nfs_get_root(s, mntfh);
@@ -2044,6 +2097,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
 out:
        kfree(data->nfs_server.hostname);
        kfree(data->mount_server.hostname);
+       kfree(data->fscache_uniq);
        security_free_mnt_opts(&data->lsm_opts);
 out_free_fh:
        kfree(mntfh);
@@ -2057,8 +2111,7 @@ out_err_nosb:
 error_splat_root:
        dput(mntroot);
 error_splat_super:
-       up_write(&s->s_umount);
-       deactivate_super(s);
+       deactivate_locked_super(s);
        goto out;
 }
 
@@ -2071,6 +2124,7 @@ static void nfs_kill_super(struct super_block *s)
 
        bdi_unregister(&server->backing_dev_info);
        kill_anon_super(s);
+       nfs_fscache_release_super_cookie(s);
        nfs_free_server(server);
 }
 
@@ -2153,8 +2207,7 @@ out_err_noserver:
        return error;
 
 error_splat_super:
-       up_write(&s->s_umount);
-       deactivate_super(s);
+       deactivate_locked_super(s);
        dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error);
        return error;
 }
@@ -2378,6 +2431,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs4_fill_super(s);
+               nfs_fscache_get_super_cookie(s, data);
        }
 
        mntroot = nfs4_get_root(s, mntfh);
@@ -2399,6 +2453,7 @@ out:
        kfree(data->client_address);
        kfree(data->nfs_server.export_path);
        kfree(data->nfs_server.hostname);
+       kfree(data->fscache_uniq);
        security_free_mnt_opts(&data->lsm_opts);
 out_free_fh:
        kfree(mntfh);
@@ -2412,8 +2467,7 @@ out_free:
 error_splat_root:
        dput(mntroot);
 error_splat_super:
-       up_write(&s->s_umount);
-       deactivate_super(s);
+       deactivate_locked_super(s);
        goto out;
 }
 
@@ -2421,10 +2475,11 @@ static void nfs4_kill_super(struct super_block *sb)
 {
        struct nfs_server *server = NFS_SB(sb);
 
-       nfs_return_all_delegations(sb);
+       nfs_super_return_all_delegations(sb);
        kill_anon_super(sb);
 
        nfs4_renewd_prepare_shutdown(server);
+       nfs_fscache_release_super_cookie(sb);
        nfs_free_server(server);
 }
 
@@ -2459,7 +2514,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
                compare_super = NULL;
 
        /* Get a superblock - note that we may end up sharing one that already exists */
-       s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
+       s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
        if (IS_ERR(s)) {
                error = PTR_ERR(s);
                goto out_err_nosb;
@@ -2506,8 +2561,7 @@ out_err_noserver:
        return error;
 
 error_splat_super:
-       up_write(&s->s_umount);
-       deactivate_super(s);
+       deactivate_locked_super(s);
        dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error);
        return error;
 }
@@ -2544,7 +2598,7 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
                compare_super = NULL;
 
        /* Get a superblock - note that we may end up sharing one that already exists */
-       s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
+       s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
        if (IS_ERR(s)) {
                error = PTR_ERR(s);
                goto out_err_nosb;
@@ -2591,8 +2645,7 @@ out_err_noserver:
        return error;
 
 error_splat_super:
-       up_write(&s->s_umount);
-       deactivate_super(s);
+       deactivate_locked_super(s);
        dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
        return error;
 }