aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-11-04 15:33:38 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-11-04 15:33:38 -0500
commitd530838bfa507d67b40d13b00d9cbd7a46a47e78 (patch)
treef4b2be26c0a7b9ed3233a2be016b7e97427f8705 /fs/nfs/nfs4proc.c
parent4cecb76ff86db46d2823550256c828b6597f418e (diff)
NFSv4: Fix problem with OPEN_DOWNGRADE
RFC 3530 states that for OPEN_DOWNGRADE "The share_access and share_deny bits specified must be exactly equal to the union of the share_access and share_deny bits specified for some subset of the OPENs in effect for current openowner on the current file. Setattr is currently violating the NFSv4 rules for OPEN_DOWNGRADE in that it may cause a downgrade from OPEN4_SHARE_ACCESS_BOTH to OPEN4_SHARE_ACCESS_WRITE despite the fact that there exists no open file with O_WRONLY access mode. Fix the problem by replacing nfs4_find_state() with a modified version of nfs_find_open_context(). Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c23
1 files changed, 10 insertions, 13 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 02fddd0e27e8..9e492c2261c0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -214,7 +214,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid,
214 struct inode *inode = state->inode; 214 struct inode *inode = state->inode;
215 215
216 open_flags &= (FMODE_READ|FMODE_WRITE); 216 open_flags &= (FMODE_READ|FMODE_WRITE);
217 /* Protect against nfs4_find_state() */ 217 /* Protect against nfs4_find_state_byowner() */
218 spin_lock(&state->owner->so_lock); 218 spin_lock(&state->owner->so_lock);
219 spin_lock(&inode->i_lock); 219 spin_lock(&inode->i_lock);
220 memcpy(&state->stateid, stateid, sizeof(state->stateid)); 220 memcpy(&state->stateid, stateid, sizeof(state->stateid));
@@ -1274,7 +1274,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
1274{ 1274{
1275 struct rpc_cred *cred; 1275 struct rpc_cred *cred;
1276 struct inode *inode = dentry->d_inode; 1276 struct inode *inode = dentry->d_inode;
1277 struct nfs4_state *state; 1277 struct nfs_open_context *ctx;
1278 struct nfs4_state *state = NULL;
1278 int status; 1279 int status;
1279 1280
1280 nfs_fattr_init(fattr); 1281 nfs_fattr_init(fattr);
@@ -1282,22 +1283,18 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
1282 cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); 1283 cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
1283 if (IS_ERR(cred)) 1284 if (IS_ERR(cred))
1284 return PTR_ERR(cred); 1285 return PTR_ERR(cred);
1285 /* Search for an existing WRITE delegation first */ 1286
1286 state = nfs4_open_delegated(inode, FMODE_WRITE, cred); 1287 /* Search for an existing open(O_WRITE) file */
1287 if (!IS_ERR(state)) { 1288 ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
1288 /* NB: nfs4_open_delegated() bumps the inode->i_count */ 1289 if (ctx != NULL)
1289 iput(inode); 1290 state = ctx->state;
1290 } else {
1291 /* Search for an existing open(O_WRITE) stateid */
1292 state = nfs4_find_state(inode, cred, FMODE_WRITE);
1293 }
1294 1291
1295 status = nfs4_do_setattr(NFS_SERVER(inode), fattr, 1292 status = nfs4_do_setattr(NFS_SERVER(inode), fattr,
1296 NFS_FH(inode), sattr, state); 1293 NFS_FH(inode), sattr, state);
1297 if (status == 0) 1294 if (status == 0)
1298 nfs_setattr_update_inode(inode, sattr); 1295 nfs_setattr_update_inode(inode, sattr);
1299 if (state != NULL) 1296 if (ctx != NULL)
1300 nfs4_close_state(state, FMODE_WRITE); 1297 put_nfs_open_context(ctx);
1301 put_rpccred(cred); 1298 put_rpccred(cred);
1302 return status; 1299 return status;
1303} 1300}