]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/nfs/super.c
Merge branch 'next'
[linux-2.6-omap-h63xx.git] / fs / nfs / super.c
index ffb697416cb175aa19252d4e0ac0f48806d8733f..8b28b95c9e44a6cafe221609111a05bb0c495361 100644 (file)
@@ -91,6 +91,7 @@ enum {
        /* Mount options that take string arguments */
        Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
        Opt_addr, Opt_mountaddr, Opt_clientaddr,
+       Opt_lookupcache,
 
        /* Special mount options */
        Opt_userspace, Opt_deprecated, Opt_sloppy,
@@ -154,6 +155,8 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_mounthost, "mounthost=%s" },
        { Opt_mountaddr, "mountaddr=%s" },
 
+       { Opt_lookupcache, "lookupcache=%s" },
+
        { Opt_err, NULL }
 };
 
@@ -200,6 +203,22 @@ static const match_table_t nfs_secflavor_tokens = {
        { Opt_sec_err, NULL }
 };
 
+enum {
+       Opt_lookupcache_all, Opt_lookupcache_positive,
+       Opt_lookupcache_none,
+
+       Opt_lookupcache_err
+};
+
+static match_table_t nfs_lookupcache_tokens = {
+       { Opt_lookupcache_all, "all" },
+       { Opt_lookupcache_positive, "pos" },
+       { Opt_lookupcache_positive, "positive" },
+       { Opt_lookupcache_none, "none" },
+
+       { Opt_lookupcache_err, NULL }
+};
+
 
 static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct dentry *, struct kstatfs *);
@@ -209,7 +228,6 @@ 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 int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
 
 static struct file_system_type nfs_fs_type = {
@@ -232,7 +250,6 @@ 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,
@@ -337,26 +354,20 @@ void __exit unregister_nfs_fs(void)
        unregister_filesystem(&nfs_fs_type);
 }
 
-void nfs_sb_active(struct nfs_server *server)
+void nfs_sb_active(struct super_block *sb)
 {
-       atomic_inc(&server->active);
-}
+       struct nfs_server *server = NFS_SB(sb);
 
-void nfs_sb_deactive(struct nfs_server *server)
-{
-       if (atomic_dec_and_test(&server->active))
-               wake_up(&server->active_wq);
+       if (atomic_inc_return(&server->active) == 1)
+               atomic_inc(&sb->s_active);
 }
 
-static void nfs_put_super(struct super_block *sb)
+void nfs_sb_deactive(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);
+
+       if (atomic_dec_and_test(&server->active))
+               deactivate_super(sb);
 }
 
 /*
@@ -663,25 +674,6 @@ static void nfs_umount_begin(struct super_block *sb)
                rpc_killall_tasks(rpc);
 }
 
-/*
- * Set the port number in an address.  Be agnostic about the address family.
- */
-static void nfs_set_port(struct sockaddr *sap, unsigned short port)
-{
-       switch (sap->sa_family) {
-       case AF_INET: {
-               struct sockaddr_in *ap = (struct sockaddr_in *)sap;
-               ap->sin_port = htons(port);
-               break;
-       }
-       case AF_INET6: {
-               struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap;
-               ap->sin6_port = htons(port);
-               break;
-       }
-       }
-}
-
 /*
  * Sanity-check a server address provided by the mount command.
  *
@@ -724,20 +716,22 @@ static void nfs_parse_ipv4_address(char *string, size_t str_len,
        *addr_len = 0;
 }
 
-#define IPV6_SCOPE_DELIMITER   '%'
-
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
-                                   const char *delim,
-                                   struct sockaddr_in6 *sin6)
+static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
+                                  const char *delim,
+                                  struct sockaddr_in6 *sin6)
 {
        char *p;
        size_t len;
 
-       if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
-               return ;
+       if ((string + str_len) == delim)
+               return 1;
+
        if (*delim != IPV6_SCOPE_DELIMITER)
-               return;
+               return 0;
+
+       if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
+               return 0;
 
        len = (string + str_len) - delim - 1;
        p = kstrndup(delim + 1, len, GFP_KERNEL);
@@ -750,14 +744,20 @@ static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
                        scope_id = dev->ifindex;
                        dev_put(dev);
                } else {
-                       /* scope_id is set to zero on error */
-                       strict_strtoul(p, 10, &scope_id);
+                       if (strict_strtoul(p, 10, &scope_id) == 0) {
+                               kfree(p);
+                               return 0;
+                       }
                }
 
                kfree(p);
+
                sin6->sin6_scope_id = scope_id;
                dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
+               return 1;
        }
+
+       return 0;
 }
 
 static void nfs_parse_ipv6_address(char *string, size_t str_len,
@@ -773,9 +773,11 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len,
 
                sin6->sin6_family = AF_INET6;
                *addr_len = sizeof(*sin6);
-               if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) {
-                       nfs_parse_ipv6_scope_id(string, str_len, delim, sin6);
-                       return;
+               if (in6_pton(string, str_len, addr,
+                                       IPV6_SCOPE_DELIMITER, &delim) != 0) {
+                       if (nfs_parse_ipv6_scope_id(string, str_len,
+                                                       delim, sin6) != 0)
+                               return;
                }
        }
 
@@ -798,7 +800,7 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len,
  * If there is a problem constructing the new sockaddr, set the address
  * family to AF_UNSPEC.
  */
-static void nfs_parse_ip_address(char *string, size_t str_len,
+void nfs_parse_ip_address(char *string, size_t str_len,
                                 struct sockaddr *sap, size_t *addr_len)
 {
        unsigned int i, colons;
@@ -1258,6 +1260,30 @@ static int nfs_parse_mount_options(char *raw,
                                             &mnt->mount_server.addrlen);
                        kfree(string);
                        break;
+               case Opt_lookupcache:
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       token = match_token(string,
+                                       nfs_lookupcache_tokens, args);
+                       kfree(string);
+                       switch (token) {
+                               case Opt_lookupcache_all:
+                                       mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
+                                       break;
+                               case Opt_lookupcache_positive:
+                                       mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
+                                       mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
+                                       break;
+                               case Opt_lookupcache_none:
+                                       mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
+                                       break;
+                               default:
+                                       errors++;
+                                       dfprintk(MOUNT, "NFS:   invalid "
+                                                       "lookupcache argument\n");
+                       };
+                       break;
 
                /*
                 * Special options
@@ -1558,7 +1584,7 @@ static int nfs_validate_mount_data(void *options,
                 * Translate to nfs_parsed_mount_data, which nfs_fill_super
                 * can deal with.
                 */
-               args->flags             = data->flags;
+               args->flags             = data->flags & NFS_MOUNT_FLAGMASK;
                args->rsize             = data->rsize;
                args->wsize             = data->wsize;
                args->timeo             = data->timeo;