]> err.no Git - linux-2.6/blobdiff - fs/nfs/nfs4state.c
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / fs / nfs / nfs4state.c
index ac816b303f3aa9cfdb7f948fdba332b8b9455876..23a9a36556bf5f5ca4dba357157cbb35dc9ac331 100644 (file)
@@ -38,6 +38,7 @@
  * subsequent patch.
  */
 
+#include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/nfs_fs.h>
@@ -155,8 +156,9 @@ static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
 }
 
 static struct nfs4_state_owner *
-nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred)
+nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred)
 {
+       struct nfs_client *clp = server->nfs_client;
        struct rb_node **p = &clp->cl_state_owners.rb_node,
                       *parent = NULL;
        struct nfs4_state_owner *sp, *res = NULL;
@@ -165,6 +167,14 @@ nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred)
                parent = *p;
                sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);
 
+               if (server < sp->so_server) {
+                       p = &parent->rb_left;
+                       continue;
+               }
+               if (server > sp->so_server) {
+                       p = &parent->rb_right;
+                       continue;
+               }
                if (cred < sp->so_cred)
                        p = &parent->rb_left;
                else if (cred > sp->so_cred)
@@ -189,6 +199,14 @@ nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new)
                parent = *p;
                sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);
 
+               if (new->so_server < sp->so_server) {
+                       p = &parent->rb_left;
+                       continue;
+               }
+               if (new->so_server > sp->so_server) {
+                       p = &parent->rb_right;
+                       continue;
+               }
                if (new->so_cred < sp->so_cred)
                        p = &parent->rb_left;
                else if (new->so_cred > sp->so_cred)
@@ -259,7 +277,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
        struct nfs4_state_owner *sp, *new;
 
        spin_lock(&clp->cl_lock);
-       sp = nfs4_find_state_owner(clp, cred);
+       sp = nfs4_find_state_owner(server, cred);
        spin_unlock(&clp->cl_lock);
        if (sp != NULL)
                return sp;
@@ -267,6 +285,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
        if (new == NULL)
                return NULL;
        new->so_client = clp;
+       new->so_server = server;
        new->so_cred = cred;
        spin_lock(&clp->cl_lock);
        sp = nfs4_insert_state_owner(clp, new);
@@ -306,6 +325,7 @@ nfs4_alloc_open_state(void)
        atomic_set(&state->count, 1);
        INIT_LIST_HEAD(&state->lock_states);
        spin_lock_init(&state->state_lock);
+       seqlock_init(&state->seqlock);
        return state;
 }
 
@@ -321,8 +341,6 @@ nfs4_state_set_mode_locked(struct nfs4_state *state, mode_t mode)
                else
                        list_move_tail(&state->open_states, &state->owner->so_states);
        }
-       if (mode == 0)
-               list_del_init(&state->inode_states);
        state->state = mode;
 }
 
@@ -395,8 +413,7 @@ void nfs4_put_open_state(struct nfs4_state *state)
        if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
                return;
        spin_lock(&inode->i_lock);
-       if (!list_empty(&state->inode_states))
-               list_del(&state->inode_states);
+       list_del(&state->inode_states);
        list_del(&state->open_states);
        spin_unlock(&inode->i_lock);
        spin_unlock(&owner->so_lock);
@@ -408,16 +425,15 @@ void nfs4_put_open_state(struct nfs4_state *state)
 /*
  * Close the current file.
  */
-void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
+static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mode, int wait)
 {
-       struct inode *inode = state->inode;
        struct nfs4_state_owner *owner = state->owner;
-       int oldstate, newstate = 0;
+       int call_close = 0;
+       int newstate;
 
        atomic_inc(&owner->so_count);
        /* Protect against nfs4_find_state() */
        spin_lock(&owner->so_lock);
-       spin_lock(&inode->i_lock);
        switch (mode & (FMODE_READ | FMODE_WRITE)) {
                case FMODE_READ:
                        state->n_rdonly--;
@@ -428,25 +444,39 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
                case FMODE_READ|FMODE_WRITE:
                        state->n_rdwr--;
        }
-       oldstate = newstate = state->state;
+       newstate = FMODE_READ|FMODE_WRITE;
        if (state->n_rdwr == 0) {
-               if (state->n_rdonly == 0)
+               if (state->n_rdonly == 0) {
                        newstate &= ~FMODE_READ;
-               if (state->n_wronly == 0)
+                       call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
+                       call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+               }
+               if (state->n_wronly == 0) {
                        newstate &= ~FMODE_WRITE;
+                       call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
+                       call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+               }
+               if (newstate == 0)
+                       clear_bit(NFS_DELEGATED_STATE, &state->flags);
        }
-       if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
-               nfs4_state_set_mode_locked(state, newstate);
-               oldstate = newstate;
-       }
-       spin_unlock(&inode->i_lock);
+       nfs4_state_set_mode_locked(state, newstate);
        spin_unlock(&owner->so_lock);
 
-       if (oldstate == newstate) {
+       if (!call_close) {
                nfs4_put_open_state(state);
                nfs4_put_state_owner(owner);
        } else
-               nfs4_do_close(path, state);
+               nfs4_do_close(path, state, wait);
+}
+
+void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
+{
+       __nfs4_close(path, state, mode, 0);
+}
+
+void nfs4_close_sync(struct path *path, struct nfs4_state *state, mode_t mode)
+{
+       __nfs4_close(path, state, mode, 1);
 }
 
 /*
@@ -592,8 +622,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
 void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
 {
        struct nfs4_lock_state *lsp;
+       int seq;
 
-       memcpy(dst, &state->stateid, sizeof(*dst));
+       do {
+               seq = read_seqbegin(&state->seqlock);
+               memcpy(dst, &state->stateid, sizeof(*dst));
+       } while (read_seqretry(&state->seqlock, seq));
        if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
                return;
 
@@ -642,6 +676,12 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
                case 0:
                        break;
                case -NFS4ERR_BAD_SEQID:
+                       if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
+                               return;
+                       printk(KERN_WARNING "NFS: v4 server returned a bad"
+                                       "sequence-id error on an"
+                                       "unconfirmed sequence %p!\n",
+                                       seqid->sequence);
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_BAD_STATEID:
@@ -744,7 +784,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s
        for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
-               if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
+               if (nfs_file_open_context(fl->fl_file)->state != state)
                        continue;
                status = ops->recover_lock(state, fl);
                if (status >= 0)
@@ -838,6 +878,10 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp)
                sp->so_seqid.flags = 0;
                spin_lock(&sp->so_lock);
                list_for_each_entry(state, &sp->so_states, open_states) {
+                       clear_bit(NFS_DELEGATED_STATE, &state->flags);
+                       clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+                       clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+                       clear_bit(NFS_O_RDWR_STATE, &state->flags);
                        list_for_each_entry(lock, &state->lock_states, ls_locks) {
                                lock->ls_seqid.counter = 0;
                                lock->ls_seqid.flags = 0;