]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/delegation.c
Merge tag 'boards' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[karo-tx-linux.git] / fs / nfs / delegation.c
index 7f2654069806f011c4361900041ef6ae64f17de4..89af1d269274f3a91401f704226dec43f9c02528 100644 (file)
@@ -105,7 +105,7 @@ again:
                        continue;
                if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
                        continue;
-               if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
+               if (!nfs4_stateid_match(&state->stateid, stateid))
                        continue;
                get_nfs_open_context(ctx);
                spin_unlock(&inode->i_lock);
@@ -139,8 +139,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
        if (delegation != NULL) {
                spin_lock(&delegation->lock);
                if (delegation->inode != NULL) {
-                       memcpy(delegation->stateid.data, res->delegation.data,
-                              sizeof(delegation->stateid.data));
+                       nfs4_stateid_copy(&delegation->stateid, &res->delegation);
                        delegation->type = res->delegation_type;
                        delegation->maxsize = res->maxsize;
                        oldcred = delegation->cred;
@@ -236,8 +235,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
        if (delegation == NULL)
                return -ENOMEM;
-       memcpy(delegation->stateid.data, res->delegation.data,
-                       sizeof(delegation->stateid.data));
+       nfs4_stateid_copy(&delegation->stateid, &res->delegation);
        delegation->type = res->delegation_type;
        delegation->maxsize = res->maxsize;
        delegation->change_attr = inode->i_version;
@@ -250,19 +248,22 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        old_delegation = rcu_dereference_protected(nfsi->delegation,
                                        lockdep_is_held(&clp->cl_lock));
        if (old_delegation != NULL) {
-               if (memcmp(&delegation->stateid, &old_delegation->stateid,
-                                       sizeof(old_delegation->stateid)) == 0 &&
+               if (nfs4_stateid_match(&delegation->stateid,
+                                       &old_delegation->stateid) &&
                                delegation->type == old_delegation->type) {
                        goto out;
                }
                /*
                 * Deal with broken servers that hand out two
                 * delegations for the same file.
+                * Allow for upgrades to a WRITE delegation, but
+                * nothing else.
                 */
                dfprintk(FILE, "%s: server %s handed out "
                                "a duplicate delegation!\n",
                                __func__, clp->cl_hostname);
-               if (delegation->type <= old_delegation->type) {
+               if (delegation->type == old_delegation->type ||
+                   !(delegation->type & FMODE_WRITE)) {
                        freeme = delegation;
                        delegation = NULL;
                        goto out;
@@ -455,17 +456,24 @@ static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp,
        rcu_read_unlock();
 }
 
-static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
-{
-       nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
-}
-
 static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 {
        if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
                nfs4_schedule_state_manager(clp);
 }
 
+void nfs_remove_bad_delegation(struct inode *inode)
+{
+       struct nfs_delegation *delegation;
+
+       delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode));
+       if (delegation) {
+               nfs_inode_find_state_and_recover(inode, &delegation->stateid);
+               nfs_free_delegation(delegation);
+       }
+}
+EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
+
 /**
  * nfs_expire_all_delegation_types
  * @clp: client to process
@@ -488,18 +496,6 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
        nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
 }
 
-/**
- * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
- * @clp: client to process
- *
- */
-void nfs_handle_cb_pathdown(struct nfs_client *clp)
-{
-       if (clp == NULL)
-               return;
-       nfs_client_mark_return_all_delegations(clp);
-}
-
 static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
 {
        struct nfs_delegation *delegation;
@@ -531,7 +527,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
 /**
  * nfs_async_inode_return_delegation - asynchronously return a delegation
  * @inode: inode to process
- * @stateid: state ID information from CB_RECALL arguments
+ * @stateid: state ID information
  *
  * Returns zero on success, or a negative errno value.
  */
@@ -545,7 +541,7 @@ int nfs_async_inode_return_delegation(struct inode *inode,
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
 
-       if (!clp->cl_mvops->validate_stateid(delegation, stateid)) {
+       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
                rcu_read_unlock();
                return -ENOENT;
        }
@@ -684,21 +680,25 @@ int nfs_delegations_present(struct nfs_client *clp)
  * nfs4_copy_delegation_stateid - Copy inode's state ID information
  * @dst: stateid data structure to fill in
  * @inode: inode to check
+ * @flags: delegation type requirement
  *
- * Returns one and fills in "dst->data" * if inode had a delegation,
- * otherwise zero is returned.
+ * Returns "true" and fills in "dst->data" * if inode had a delegation,
+ * otherwise "false" is returned.
  */
-int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
+bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
+               fmode_t flags)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_delegation *delegation;
-       int ret = 0;
+       bool ret;
 
+       flags &= FMODE_READ|FMODE_WRITE;
        rcu_read_lock();
        delegation = rcu_dereference(nfsi->delegation);
-       if (delegation != NULL) {
-               memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
-               ret = 1;
+       ret = (delegation != NULL && (delegation->type & flags) == flags);
+       if (ret) {
+               nfs4_stateid_copy(dst, &delegation->stateid);
+               nfs_mark_delegation_referenced(delegation);
        }
        rcu_read_unlock();
        return ret;