fs: dcache remove dcache_lock
[linux-flexiantxendom0-natty.git] / fs / nfs / namespace.c
index 371b804..74aaf39 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/dcache.h>
+#include <linux/gfp.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/nfs_fs.h>
@@ -20,7 +21,7 @@
 
 static void nfs_expire_automounts(struct work_struct *work);
 
-LIST_HEAD(nfs_automount_list);
+static LIST_HEAD(nfs_automount_list);
 static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts);
 int nfs_mountpoint_expiry_timeout = 500 * HZ;
 
@@ -48,12 +49,17 @@ char *nfs_path(const char *base,
               const struct dentry *dentry,
               char *buffer, ssize_t buflen)
 {
-       char *end = buffer+buflen;
+       char *end;
        int namelen;
+       unsigned seq;
 
+rename_retry:
+       end = buffer+buflen;
        *--end = '\0';
        buflen--;
-       spin_lock(&dcache_lock);
+
+       seq = read_seqbegin(&rename_lock);
+       rcu_read_lock();
        while (!IS_ROOT(dentry) && dentry != droot) {
                namelen = dentry->d_name.len;
                buflen -= namelen + 1;
@@ -64,7 +70,14 @@ char *nfs_path(const char *base,
                *--end = '/';
                dentry = dentry->d_parent;
        }
-       spin_unlock(&dcache_lock);
+       rcu_read_unlock();
+       if (read_seqretry(&rename_lock, seq))
+               goto rename_retry;
+       if (*end != '/') {
+               if (--buflen < 0)
+                       goto Elong;
+               *--end = '/';
+       }
        namelen = strlen(base);
        /* Strip off excess slashes in base string */
        while (namelen > 0 && base[namelen - 1] == '/')
@@ -76,7 +89,9 @@ char *nfs_path(const char *base,
        memcpy(end, base, namelen);
        return end;
 Elong_unlock:
-       spin_unlock(&dcache_lock);
+       rcu_read_unlock();
+       if (read_seqretry(&rename_lock, seq))
+               goto rename_retry;
 Elong:
        return ERR_PTR(-ENAMETOOLONG);
 }
@@ -99,68 +114,81 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
        struct vfsmount *mnt;
        struct nfs_server *server = NFS_SERVER(dentry->d_inode);
        struct dentry *parent;
-       struct nfs_fh fh;
-       struct nfs_fattr fattr;
+       struct nfs_fh *fh = NULL;
+       struct nfs_fattr *fattr = NULL;
        int err;
 
        dprintk("--> nfs_follow_mountpoint()\n");
 
-       BUG_ON(IS_ROOT(dentry));
-       dprintk("%s: enter\n", __FUNCTION__);
-       dput(nd->dentry);
-       nd->dentry = dget(dentry);
+       err = -ESTALE;
+       if (IS_ROOT(dentry))
+               goto out_err;
+
+       err = -ENOMEM;
+       fh = nfs_alloc_fhandle();
+       fattr = nfs_alloc_fattr();
+       if (fh == NULL || fattr == NULL)
+               goto out_err;
+
+       dprintk("%s: enter\n", __func__);
+       dput(nd->path.dentry);
+       nd->path.dentry = dget(dentry);
 
        /* Look it up again */
-       parent = dget_parent(nd->dentry);
+       parent = dget_parent(nd->path.dentry);
        err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
-                                                 &nd->dentry->d_name,
-                                                 &fh, &fattr);
+                                                 &nd->path.dentry->d_name,
+                                                 fh, fattr);
        dput(parent);
        if (err != 0)
                goto out_err;
 
-       if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL)
-               mnt = nfs_do_refmount(nd->mnt, nd->dentry);
+       if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
+               mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry);
        else
-               mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr);
+               mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh,
+                                     fattr);
        err = PTR_ERR(mnt);
        if (IS_ERR(mnt))
                goto out_err;
 
        mntget(mnt);
-       err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list);
+       err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE,
+                          &nfs_automount_list);
        if (err < 0) {
                mntput(mnt);
                if (err == -EBUSY)
                        goto out_follow;
                goto out_err;
        }
-       mntput(nd->mnt);
-       dput(nd->dentry);
-       nd->mnt = mnt;
-       nd->dentry = dget(mnt->mnt_root);
+       path_put(&nd->path);
+       nd->path.mnt = mnt;
+       nd->path.dentry = dget(mnt->mnt_root);
        schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
 out:
-       dprintk("%s: done, returned %d\n", __FUNCTION__, err);
+       nfs_free_fattr(fattr);
+       nfs_free_fhandle(fh);
+       dprintk("%s: done, returned %d\n", __func__, err);
 
        dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
        return ERR_PTR(err);
 out_err:
-       path_release(nd);
+       path_put(&nd->path);
        goto out;
 out_follow:
-       while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+       while (d_mountpoint(nd->path.dentry) &&
+              follow_down(&nd->path))
                ;
        err = 0;
        goto out;
 }
 
-struct inode_operations nfs_mountpoint_inode_operations = {
+const struct inode_operations nfs_mountpoint_inode_operations = {
        .follow_link    = nfs_follow_mountpoint,
        .getattr        = nfs_getattr,
 };
 
-struct inode_operations nfs_referral_inode_operations = {
+const struct inode_operations nfs_referral_inode_operations = {
        .follow_link    = nfs_follow_mountpoint,
 };
 
@@ -175,10 +203,8 @@ static void nfs_expire_automounts(struct work_struct *work)
 
 void nfs_release_automount_timer(void)
 {
-       if (list_empty(&nfs_automount_list)) {
+       if (list_empty(&nfs_automount_list))
                cancel_delayed_work(&nfs_automount_task);
-               flush_scheduled_work();
-       }
 }
 
 /*
@@ -189,8 +215,8 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
                                           struct nfs_clone_mount *mountdata)
 {
 #ifdef CONFIG_NFS_V4
-       struct vfsmount *mnt = NULL;
-       switch (server->nfs_client->cl_nfsversion) {
+       struct vfsmount *mnt = ERR_PTR(-EINVAL);
+       switch (server->nfs_client->rpc_ops->version) {
                case 2:
                case 3:
                        mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
@@ -229,7 +255,7 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
 
        dprintk("--> nfs_do_submount()\n");
 
-       dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
+       dprintk("%s: submounting on %s/%s\n", __func__,
                        dentry->d_parent->d_name.name,
                        dentry->d_name.name);
        if (page == NULL)
@@ -242,7 +268,7 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
 free_page:
        free_page((unsigned long)page);
 out:
-       dprintk("%s: done\n", __FUNCTION__);
+       dprintk("%s: done\n", __func__);
 
        dprintk("<-- nfs_do_submount() = %p\n", mnt);
        return mnt;