]> err.no Git - linux-2.6/blobdiff - fs/nfs/inode.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / fs / nfs / inode.c
index 6c22453d77aea6071622f6d2d104d1b6c258d223..5cb3345eb6940a7532457f447d7ea77d89b86113 100644 (file)
@@ -192,7 +192,7 @@ void nfs_invalidate_atime(struct inode *inode)
  */
 static void nfs_invalidate_inode(struct inode *inode)
 {
-       set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
+       set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
        nfs_zap_caches_locked(inode);
 }
 
@@ -229,7 +229,7 @@ nfs_init_locked(struct inode *inode, void *opaque)
        struct nfs_find_desc    *desc = (struct nfs_find_desc *)opaque;
        struct nfs_fattr        *fattr = desc->fattr;
 
-       NFS_FILEID(inode) = fattr->fileid;
+       set_nfs_fileid(inode, fattr->fileid);
        nfs_copy_fh(NFS_FH(inode), desc->fh);
        return 0;
 }
@@ -291,7 +291,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                        inode->i_fop = &nfs_dir_operations;
                        if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
                            && fattr->size <= NFS_LIMIT_READDIRPLUS)
-                               set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
+                               set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        /* Deal with crossing mountpoints */
                        if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
                                if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
@@ -299,6 +299,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                                else
                                        inode->i_op = &nfs_mountpoint_inode_operations;
                                inode->i_fop = NULL;
+                               set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags);
                        }
                } else if (S_ISLNK(inode->i_mode))
                        inode->i_op = &nfs_symlink_inode_operations;
@@ -357,6 +358,10 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 
        nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
 
+       /* skip mode change if it's just for clearing setuid/setgid */
+       if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
+               attr->ia_valid &= ~ATTR_MODE;
+
        if (attr->ia_valid & ATTR_SIZE) {
                if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
                        attr->ia_valid &= ~ATTR_SIZE;
@@ -429,15 +434,11 @@ static int nfs_wait_schedule(void *word)
  */
 static int nfs_wait_on_inode(struct inode *inode)
 {
-       struct rpc_clnt *clnt = NFS_CLIENT(inode);
        struct nfs_inode *nfsi = NFS_I(inode);
-       sigset_t oldmask;
        int error;
 
-       rpc_clnt_sigmask(clnt, &oldmask);
        error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING,
-                                       nfs_wait_schedule, TASK_INTERRUPTIBLE);
-       rpc_clnt_sigunmask(clnt, &oldmask);
+                                       nfs_wait_schedule, TASK_KILLABLE);
 
        return error;
 }
@@ -457,9 +458,18 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
        int err;
 
-       /* Flush out writes to the server in order to update c/mtime */
-       if (S_ISREG(inode->i_mode))
+       /*
+        * Flush out writes to the server in order to update c/mtime.
+        *
+        * Hold the i_mutex to suspend application writes temporarily;
+        * this prevents long-running writing applications from blocking
+        * nfs_wb_nocommit.
+        */
+       if (S_ISREG(inode->i_mode)) {
+               mutex_lock(&inode->i_mutex);
                nfs_wb_nocommit(inode);
+               mutex_unlock(&inode->i_mutex);
+       }
 
        /*
         * We may force a getattr if the user cares about atime.
@@ -496,6 +506,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
                ctx->cred = get_rpccred(cred);
                ctx->state = NULL;
                ctx->lockowner = current->files;
+               ctx->flags = 0;
                ctx->error = 0;
                ctx->dir_cookie = 0;
                atomic_set(&ctx->count, 1);
@@ -510,16 +521,24 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
        return ctx;
 }
 
-void put_nfs_open_context(struct nfs_open_context *ctx)
+static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
 {
-       struct inode *inode = ctx->path.dentry->d_inode;
+       struct inode *inode;
+
+       if (ctx == NULL)
+               return;
 
+       inode = ctx->path.dentry->d_inode;
        if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
                return;
        list_del(&ctx->list);
        spin_unlock(&inode->i_lock);
-       if (ctx->state != NULL)
-               nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
+       if (ctx->state != NULL) {
+               if (wait)
+                       nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
+               else
+                       nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
+       }
        if (ctx->cred != NULL)
                put_rpccred(ctx->cred);
        dput(ctx->path.dentry);
@@ -527,6 +546,16 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
        kfree(ctx);
 }
 
+void put_nfs_open_context(struct nfs_open_context *ctx)
+{
+       __put_nfs_open_context(ctx, 0);
+}
+
+static void put_nfs_open_context_sync(struct nfs_open_context *ctx)
+{
+       __put_nfs_open_context(ctx, 1);
+}
+
 /*
  * Ensure that mmap has a recent RPC credential for use when writing out
  * shared pages
@@ -573,7 +602,7 @@ static void nfs_file_clear_open_context(struct file *filp)
                spin_lock(&inode->i_lock);
                list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
                spin_unlock(&inode->i_lock);
-               put_nfs_open_context(ctx);
+               put_nfs_open_context_sync(ctx);
        }
 }
 
@@ -585,7 +614,7 @@ int nfs_open(struct inode *inode, struct file *filp)
        struct nfs_open_context *ctx;
        struct rpc_cred *cred;
 
-       cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+       cred = rpc_lookup_cred();
        if (IS_ERR(cred))
                return PTR_ERR(cred);
        ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred);
@@ -641,7 +670,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                if (status == -ESTALE) {
                        nfs_zap_caches(inode);
                        if (!S_ISDIR(inode->i_mode))
-                               set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
+                               set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
                }
                goto out;
        }
@@ -796,8 +825,9 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        if (S_ISDIR(inode->i_mode))
                                nfsi->cache_validity |= NFS_INO_INVALID_DATA;
                }
-               if (inode->i_size == fattr->pre_size && nfsi->npages == 0)
-                       inode->i_size = fattr->size;
+               if (inode->i_size == nfs_size_to_loff_t(fattr->pre_size) &&
+                   nfsi->npages == 0)
+                       inode->i_size = nfs_size_to_loff_t(fattr->size);
        }
 }
 
@@ -979,8 +1009,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 
        server = NFS_SERVER(inode);
        /* Update the fsid? */
-       if (S_ISDIR(inode->i_mode)
-                       && !nfs_fsid_equal(&server->fsid, &fattr->fsid))
+       if (S_ISDIR(inode->i_mode) &&
+                       !nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
+                       !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
                server->fsid = fattr->fsid;
 
        /*
@@ -1001,7 +1032,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        dprintk("NFS: mtime change on server for file %s/%ld\n",
                                        inode->i_sb->s_id, inode->i_ino);
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
-                       nfsi->cache_change_attribute = now;
+                       if (S_ISDIR(inode->i_mode))
+                               nfs_force_lookup_revalidate(inode);
                }
                /* If ctime has changed we should definitely clear access+acl caches */
                if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
@@ -1010,7 +1042,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                dprintk("NFS: change_attr change on server for file %s/%ld\n",
                                inode->i_sb->s_id, inode->i_ino);
                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-               nfsi->cache_change_attribute = now;
+               if (S_ISDIR(inode->i_mode))
+                       nfs_force_lookup_revalidate(inode);
        }
 
        /* Check if our cached file size is stale */
@@ -1115,7 +1148,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 void nfs4_clear_inode(struct inode *inode)
 {
        /* If we are holding a delegation, return it! */
-       nfs_inode_return_delegation(inode);
+       nfs_inode_return_delegation_noreclaim(inode);
        /* First call standard NFS clear_inode() code */
        nfs_clear_inode(inode);
 }
@@ -1165,6 +1198,9 @@ static void init_once(struct kmem_cache * cachep, void *foo)
        INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
        nfsi->ncommit = 0;
        nfsi->npages = 0;
+       atomic_set(&nfsi->silly_count, 1);
+       INIT_HLIST_HEAD(&nfsi->silly_list);
+       init_waitqueue_head(&nfsi->waitqueue);
        nfs4_init_once(nfsi);
 }
 
@@ -1186,6 +1222,36 @@ static void nfs_destroy_inodecache(void)
        kmem_cache_destroy(nfs_inode_cachep);
 }
 
+struct workqueue_struct *nfsiod_workqueue;
+
+/*
+ * start up the nfsiod workqueue
+ */
+static int nfsiod_start(void)
+{
+       struct workqueue_struct *wq;
+       dprintk("RPC:       creating workqueue nfsiod\n");
+       wq = create_singlethread_workqueue("nfsiod");
+       if (wq == NULL)
+               return -ENOMEM;
+       nfsiod_workqueue = wq;
+       return 0;
+}
+
+/*
+ * Destroy the nfsiod workqueue
+ */
+static void nfsiod_stop(void)
+{
+       struct workqueue_struct *wq;
+
+       wq = nfsiod_workqueue;
+       if (wq == NULL)
+               return;
+       nfsiod_workqueue = NULL;
+       destroy_workqueue(wq);
+}
+
 /*
  * Initialize NFS
  */
@@ -1193,6 +1259,10 @@ static int __init init_nfs_fs(void)
 {
        int err;
 
+       err = nfsiod_start();
+       if (err)
+               goto out6;
+
        err = nfs_fs_proc_init();
        if (err)
                goto out5;
@@ -1239,6 +1309,8 @@ out3:
 out4:
        nfs_fs_proc_exit();
 out5:
+       nfsiod_stop();
+out6:
        return err;
 }
 
@@ -1254,6 +1326,7 @@ static void __exit exit_nfs_fs(void)
 #endif
        unregister_nfs_fs();
        nfs_fs_proc_exit();
+       nfsiod_stop();
 }
 
 /* Not quite true; I just maintain it */