diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 13:16:29 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 16:07:35 -0400 |
commit | 08e9eac42edab63bce14b5c8419771f3c92aa3f4 (patch) | |
tree | 5dd77a7fa392710dab47d30ae42bfb88b932b097 /fs/nfs | |
parent | 202b50dc127cf4714ffdcc6a64f1648373f9414f (diff) |
[PATCH] NFSv4: Fix up races in nfs4_proc_setattr()
If we do not hold a valid stateid that is open for writes, there is little
point in doing an extra open of the file, as the RFC does not appear to
mandate this...
Make setattr use the correct stateid if we're holding mandatory byte
range locks.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 55 |
1 files changed, 19 insertions, 36 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 91e7fe867d58..af80b5981486 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -756,11 +756,10 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
756 | 756 | ||
757 | fattr->valid = 0; | 757 | fattr->valid = 0; |
758 | 758 | ||
759 | if (state != NULL) | 759 | if (state != NULL) { |
760 | msg.rpc_cred = state->owner->so_cred; | 760 | msg.rpc_cred = state->owner->so_cred; |
761 | if (sattr->ia_valid & ATTR_SIZE) | 761 | nfs4_copy_stateid(&arg.stateid, state, current->files); |
762 | nfs4_copy_stateid(&arg.stateid, state, NULL); | 762 | } else |
763 | else | ||
764 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 763 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
765 | 764 | ||
766 | return rpc_call_sync(server->client, &msg, 0); | 765 | return rpc_call_sync(server->client, &msg, 0); |
@@ -1124,47 +1123,31 @@ static int | |||
1124 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | 1123 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, |
1125 | struct iattr *sattr) | 1124 | struct iattr *sattr) |
1126 | { | 1125 | { |
1127 | struct inode * inode = dentry->d_inode; | 1126 | struct rpc_cred *cred; |
1128 | int size_change = sattr->ia_valid & ATTR_SIZE; | 1127 | struct inode *inode = dentry->d_inode; |
1129 | struct nfs4_state *state = NULL; | 1128 | struct nfs4_state *state; |
1130 | int need_iput = 0; | ||
1131 | int status; | 1129 | int status; |
1132 | 1130 | ||
1133 | fattr->valid = 0; | 1131 | fattr->valid = 0; |
1134 | 1132 | ||
1135 | if (size_change) { | 1133 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); |
1136 | struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1134 | if (IS_ERR(cred)) |
1137 | if (IS_ERR(cred)) | 1135 | return PTR_ERR(cred); |
1138 | return PTR_ERR(cred); | 1136 | /* Search for an existing WRITE delegation first */ |
1137 | state = nfs4_open_delegated(inode, FMODE_WRITE, cred); | ||
1138 | if (!IS_ERR(state)) { | ||
1139 | /* NB: nfs4_open_delegated() bumps the inode->i_count */ | ||
1140 | iput(inode); | ||
1141 | } else { | ||
1142 | /* Search for an existing open(O_WRITE) stateid */ | ||
1139 | state = nfs4_find_state(inode, cred, FMODE_WRITE); | 1143 | state = nfs4_find_state(inode, cred, FMODE_WRITE); |
1140 | if (state == NULL) { | ||
1141 | state = nfs4_open_delegated(dentry->d_inode, | ||
1142 | FMODE_WRITE, cred); | ||
1143 | if (IS_ERR(state)) | ||
1144 | state = nfs4_do_open(dentry->d_parent->d_inode, | ||
1145 | dentry, FMODE_WRITE, | ||
1146 | NULL, cred); | ||
1147 | need_iput = 1; | ||
1148 | } | ||
1149 | put_rpccred(cred); | ||
1150 | if (IS_ERR(state)) | ||
1151 | return PTR_ERR(state); | ||
1152 | |||
1153 | if (state->inode != inode) { | ||
1154 | printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode); | ||
1155 | status = -EIO; | ||
1156 | goto out; | ||
1157 | } | ||
1158 | } | 1144 | } |
1145 | |||
1159 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1146 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, |
1160 | NFS_FH(inode), sattr, state); | 1147 | NFS_FH(inode), sattr, state); |
1161 | out: | 1148 | if (state != NULL) |
1162 | if (state) { | ||
1163 | inode = state->inode; | ||
1164 | nfs4_close_state(state, FMODE_WRITE); | 1149 | nfs4_close_state(state, FMODE_WRITE); |
1165 | if (need_iput) | 1150 | put_rpccred(cred); |
1166 | iput(inode); | ||
1167 | } | ||
1168 | return status; | 1151 | return status; |
1169 | } | 1152 | } |
1170 | 1153 | ||