]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/nfs4proc.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[mv-sheeva.git] / fs / nfs / nfs4proc.c
index da481bda44f783ee5857d029dab46fd1c80ab592..92ce4351781459e648958e58c0cf59d106b3bc5c 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/module.h>
+#include <linux/sunrpc/bc_xprt.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -679,6 +680,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
        p->o_res.server = p->o_arg.server;
        nfs_fattr_init(&p->f_attr);
        nfs_fattr_init(&p->dir_attr);
+       p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
 }
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
@@ -710,7 +712,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
        p->o_arg.server = server;
        p->o_arg.bitmask = server->attr_bitmask;
        p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
-       p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
        if (flags & O_EXCL) {
                u32 *s = (u32 *) p->o_arg.u.verifier.data;
                s[0] = jiffies;
@@ -1172,16 +1173,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                err = _nfs4_open_delegation_recall(ctx, state, stateid);
                switch (err) {
                        case 0:
-                               return err;
+                       case -ENOENT:
+                       case -ESTALE:
+                               goto out;
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
                                /* Don't recall a delegation if it was lost */
                                nfs4_schedule_state_recovery(server->nfs_client);
-                               return err;
+                               goto out;
+                       case -ERESTARTSYS:
+                               /*
+                                * The show must go on: exit, but mark the
+                                * stateid as needing recovery.
+                                */
+                       case -NFS4ERR_ADMIN_REVOKED:
+                       case -NFS4ERR_BAD_STATEID:
+                               nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                       case -ENOMEM:
+                               err = 0;
+                               goto out;
                }
                err = nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
+out:
        return err;
 }
 
@@ -1808,6 +1823,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
        calldata->arg.stateid = &state->open_stateid;
+       if (nfs4_has_session(server->nfs_client))
+               memset(calldata->arg.stateid->data, 0, 4);    /* clear seqid */
        /* Serialization for the sequence id */
        calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
        if (calldata->arg.seqid == NULL)
@@ -2024,8 +2041,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       int status;
+
        nfs_fattr_init(info->fattr);
-       return nfs4_call_sync(server, &msg, &args, &res, 0);
+       status = nfs4_recover_expired_lease(server);
+       if (!status)
+               status = nfs4_check_client_ready(server->nfs_client);
+       if (!status)
+               status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       return status;
 }
 
 static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -3228,8 +3252,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
        ret = nfs_revalidate_inode(server, inode);
        if (ret < 0)
                return ret;
-       if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
-               nfs_zap_acl_cache(inode);
        ret = nfs4_read_cached_acl(inode, buf, buflen);
        if (ret != -ENOENT)
                return ret;
@@ -3967,8 +3989,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
        ret = nfs4_wait_for_completion_rpc_task(task);
        if (ret == 0) {
                ret = data->rpc_status;
-               if (ret == -NFS4ERR_DENIED)
-                       ret = -EAGAIN;
        } else
                data->cancelled = 1;
        rpc_put_task(task);
@@ -4056,9 +4076,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
        int err;
 
        do {
+               err = _nfs4_proc_setlk(state, cmd, request);
+               if (err == -NFS4ERR_DENIED)
+                       err = -EAGAIN;
                err = nfs4_handle_exception(NFS_SERVER(state->inode),
-                               _nfs4_proc_setlk(state, cmd, request),
-                               &exception);
+                               err, &exception);
        } while (exception.retry);
        return err;
 }
@@ -4110,8 +4132,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                goto out;
        do {
                err = _nfs4_do_setlk(state, F_SETLK, fl, 0);
-               if (err != -NFS4ERR_DELAY)
-                       break;
+               switch (err) {
+                       default:
+                               printk(KERN_ERR "%s: unhandled error %d.\n",
+                                               __func__, err);
+                       case 0:
+                       case -ESTALE:
+                               goto out;
+                       case -NFS4ERR_EXPIRED:
+                       case -NFS4ERR_STALE_CLIENTID:
+                       case -NFS4ERR_STALE_STATEID:
+                               nfs4_schedule_state_recovery(server->nfs_client);
+                               goto out;
+                       case -ERESTARTSYS:
+                               /*
+                                * The show must go on: exit, but mark the
+                                * stateid as needing recovery.
+                                */
+                       case -NFS4ERR_ADMIN_REVOKED:
+                       case -NFS4ERR_BAD_STATEID:
+                       case -NFS4ERR_OPENMODE:
+                               nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                               err = 0;
+                               goto out;
+                       case -ENOMEM:
+                       case -NFS4ERR_DENIED:
+                               /* kill_proc(fl->fl_pid, SIGLOST, 1); */
+                               err = 0;
+                               goto out;
+                       case -NFS4ERR_DELAY:
+                               break;
+               }
                err = nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
 out:
@@ -4236,6 +4287,7 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
 
        dprintk("--> %s\n", __func__);
        BUG_ON(clp == NULL);
+
        p = (u32 *)verifier.data;
        *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
        *p = htonl((u32)clp->cl_boot_time.tv_nsec);
@@ -4359,19 +4411,21 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        return status;
 }
 
-/* Reset a slot table */
-static int nfs4_reset_slot_table(struct nfs4_session *session)
+/*
+ * Reset a slot table
+ */
+static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots,
+               int old_max_slots, int ivalue)
 {
-       struct nfs4_slot_table *tbl = &session->fc_slot_table;
-       int i, max_slots = session->fc_attrs.max_reqs;
-       int old_max_slots = session->fc_slot_table.max_slots;
+       int i;
        int ret = 0;
 
-       dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__,
-               session->fc_attrs.max_reqs, tbl);
+       dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl);
 
-       /* Until we have dynamic slot table adjustment, insist
-        * upon the same slot table size */
+       /*
+        * Until we have dynamic slot table adjustment, insist
+        * upon the same slot table size
+        */
        if (max_slots != old_max_slots) {
                dprintk("%s reset slot table does't match old\n",
                        __func__);
@@ -4380,7 +4434,7 @@ static int nfs4_reset_slot_table(struct nfs4_session *session)
        }
        spin_lock(&tbl->slot_tbl_lock);
        for (i = 0; i < max_slots; ++i)
-               tbl->slots[i].seq_nr = 1;
+               tbl->slots[i].seq_nr = ivalue;
        tbl->highest_used_slotid = -1;
        spin_unlock(&tbl->slot_tbl_lock);
        dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
@@ -4390,26 +4444,60 @@ out:
        return ret;
 }
 
+/*
+ * Reset the forechannel and backchannel slot tables
+ */
+static int nfs4_reset_slot_tables(struct nfs4_session *session)
+{
+       int status;
+
+       status = nfs4_reset_slot_table(&session->fc_slot_table,
+                       session->fc_attrs.max_reqs,
+                       session->fc_slot_table.max_slots,
+                       1);
+       if (status)
+               return status;
+
+       status = nfs4_reset_slot_table(&session->bc_slot_table,
+                       session->bc_attrs.max_reqs,
+                       session->bc_slot_table.max_slots,
+                       0);
+       return status;
+}
+
+/* Destroy the slot table */
+static void nfs4_destroy_slot_tables(struct nfs4_session *session)
+{
+       if (session->fc_slot_table.slots != NULL) {
+               kfree(session->fc_slot_table.slots);
+               session->fc_slot_table.slots = NULL;
+       }
+       if (session->bc_slot_table.slots != NULL) {
+               kfree(session->bc_slot_table.slots);
+               session->bc_slot_table.slots = NULL;
+       }
+       return;
+}
+
 /*
  * Initialize slot table
  */
-static int nfs4_init_slot_table(struct nfs4_session *session)
+static int nfs4_init_slot_table(struct nfs4_slot_table *tbl,
+               int max_slots, int ivalue)
 {
-       struct nfs4_slot_table *tbl = &session->fc_slot_table;
-       int i, max_slots = session->fc_attrs.max_reqs;
+       int i;
        struct nfs4_slot *slot;
        int ret = -ENOMEM;
 
        BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE);
 
-       dprintk("--> %s: max_reqs=%u\n", __func__,
-               session->fc_attrs.max_reqs);
+       dprintk("--> %s: max_reqs=%u\n", __func__, max_slots);
 
        slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL);
        if (!slot)
                goto out;
        for (i = 0; i < max_slots; ++i)
-               slot[i].seq_nr = 1;
+               slot[i].seq_nr = ivalue;
        ret = 0;
 
        spin_lock(&tbl->slot_tbl_lock);
@@ -4429,19 +4517,30 @@ static int nfs4_init_slot_table(struct nfs4_session *session)
 out:
        dprintk("<-- %s: return %d\n", __func__, ret);
        return ret;
+
 out_free:
        kfree(slot);
        goto out;
 }
 
-/* Destroy the slot table */
-static void nfs4_destroy_slot_table(struct nfs4_session *session)
+/*
+ * Initialize the forechannel and backchannel tables
+ */
+static int nfs4_init_slot_tables(struct nfs4_session *session)
 {
-       if (session->fc_slot_table.slots == NULL)
-               return;
-       kfree(session->fc_slot_table.slots);
-       session->fc_slot_table.slots = NULL;
-       return;
+       int status;
+
+       status = nfs4_init_slot_table(&session->fc_slot_table,
+                       session->fc_attrs.max_reqs, 1);
+       if (status)
+               return status;
+
+       status = nfs4_init_slot_table(&session->bc_slot_table,
+                       session->bc_attrs.max_reqs, 0);
+       if (status)
+               nfs4_destroy_slot_tables(session);
+
+       return status;
 }
 
 struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
@@ -4464,14 +4563,24 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
 
        tbl = &session->fc_slot_table;
        spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "Slot table");
+       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
+
+       tbl = &session->bc_slot_table;
+       spin_lock_init(&tbl->slot_tbl_lock);
+       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
+
        session->clp = clp;
        return session;
 }
 
 void nfs4_destroy_session(struct nfs4_session *session)
 {
-       nfs4_destroy_slot_table(session);
+       nfs4_proc_destroy_session(session);
+       dprintk("%s Destroy backchannel for xprt %p\n",
+               __func__, session->clp->cl_rpcclient->cl_xprt);
+       xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt,
+                               NFS41_BC_MIN_CALLBACKS);
+       nfs4_destroy_slot_tables(session);
        kfree(session);
 }
 
@@ -4588,7 +4697,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp)
        int status;
 
        nfs4_init_channel_attrs(&args);
-       args.flags = (SESSION4_PERSIST);
+       args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0);
 
@@ -4623,9 +4732,9 @@ int nfs4_proc_create_session(struct nfs_client *clp, int reset)
 
        /* Init or reset the fore channel */
        if (reset)
-               status = nfs4_reset_slot_table(session);
+               status = nfs4_reset_slot_tables(session);
        else
-               status = nfs4_init_slot_table(session);
+               status = nfs4_init_slot_tables(session);
        dprintk("fore channel slot table initialization returned %d\n", status);
        if (status)
                goto out;
@@ -4779,28 +4888,56 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
 
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
+struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
        .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
+       .establish_clid = nfs4_init_clientid,
+       .get_clid_cred  = nfs4_get_setclientid_cred,
 };
 
-struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = {
+#if defined(CONFIG_NFS_V4_1)
+struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
+       .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
+       .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
+       .recover_open   = nfs4_open_reclaim,
+       .recover_lock   = nfs4_lock_reclaim,
+       .establish_clid = nfs4_proc_exchange_id,
+       .get_clid_cred  = nfs4_get_exchange_id_cred,
+};
+#endif /* CONFIG_NFS_V4_1 */
+
+struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
+       .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
+       .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
+       .recover_open   = nfs4_open_expired,
+       .recover_lock   = nfs4_lock_expired,
+       .establish_clid = nfs4_init_clientid,
+       .get_clid_cred  = nfs4_get_setclientid_cred,
+};
+
+#if defined(CONFIG_NFS_V4_1)
+struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
        .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
+       .establish_clid = nfs4_proc_exchange_id,
+       .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
+#endif /* CONFIG_NFS_V4_1 */
 
 struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
        .sched_state_renewal = nfs4_proc_async_renew,
+       .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,
        .renew_lease = nfs4_proc_renew,
 };
 
 #if defined(CONFIG_NFS_V4_1)
 struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
        .sched_state_renewal = nfs41_proc_async_sequence,
+       .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,
        .renew_lease = nfs4_proc_sequence,
 };
 #endif
@@ -4809,6 +4946,20 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
  * Per minor version reboot and network partition recovery ops
  */
 
+struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = {
+       &nfs40_reboot_recovery_ops,
+#if defined(CONFIG_NFS_V4_1)
+       &nfs41_reboot_recovery_ops,
+#endif
+};
+
+struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = {
+       &nfs40_nograce_recovery_ops,
+#if defined(CONFIG_NFS_V4_1)
+       &nfs41_nograce_recovery_ops,
+#endif
+};
+
 struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = {
        &nfs40_state_renewal_ops,
 #if defined(CONFIG_NFS_V4_1)