]> Pileus Git - ~andy/linux/blobdiff - fs/nfs/delegation.c
NFSv4: Rate limit the state manager for lock reclaim warning messages
[~andy/linux] / fs / nfs / delegation.c
index 87f7544f3dce55ec1cc7b3ba487ad22a1ec4d061..89af1d269274f3a91401f704226dec43f9c02528 100644 (file)
@@ -256,11 +256,14 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
                /*
                 * 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;
@@ -453,11 +456,6 @@ 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))
@@ -474,6 +472,7 @@ void nfs_remove_bad_delegation(struct inode *inode)
                nfs_free_delegation(delegation);
        }
 }
+EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
 
 /**
  * nfs_expire_all_delegation_types
@@ -497,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;
@@ -693,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) {
+       ret = (delegation != NULL && (delegation->type & flags) == flags);
+       if (ret) {
                nfs4_stateid_copy(dst, &delegation->stateid);
-               ret = 1;
+               nfs_mark_delegation_referenced(delegation);
        }
        rcu_read_unlock();
        return ret;