aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-09-19 15:07:41 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-11 12:35:58 -0500
commit279b483174560147e9f56f79e9b1fd3bd4fc8f40 (patch)
treee6493e4e2a8fd9a7d7fdef939bdf83e683c44d24
parent0a52cb1083a662d4c417638ccdaa81df0e67494b (diff)
nfsd4: fix open downgrade, again
commit 3d02fa29dec920c597dd7b7db608a4bc71f088ce upstream. Yet another open-management regression: - nfs4_file_downgrade() doesn't remove the BOTH access bit on downgrade, so the server's idea of the stateid's access gets out of sync with the client's. If we want to keep an O_RDWR open in this case, we should do that in the file_put_access logic rather than here. - We forgot to convert v4 access to an open mode here. This logic has proven too hard to get right. In the future we may consider: - reexamining the lock/openowner relationship (locks probably don't really need to take their own references here). - adding open upgrade/downgrade support to the vfs. - removing the atomic operations. They're redundant as long as this is all under some other lock. Also, maybe some kind of additional static checking would help catch O_/NFS4_SHARE_ACCESS confusion. Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--fs/nfsd/nfs4state.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index bfe577c7676..3d893645cc6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -188,8 +188,15 @@ static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
188static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 188static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
189{ 189{
190 if (atomic_dec_and_test(&fp->fi_access[oflag])) { 190 if (atomic_dec_and_test(&fp->fi_access[oflag])) {
191 nfs4_file_put_fd(fp, O_RDWR);
192 nfs4_file_put_fd(fp, oflag); 191 nfs4_file_put_fd(fp, oflag);
192 /*
193 * It's also safe to get rid of the RDWR open *if*
194 * we no longer have need of the other kind of access
195 * or if we already have the other kind of open:
196 */
197 if (fp->fi_fds[1-oflag]
198 || atomic_read(&fp->fi_access[1 - oflag]) == 0)
199 nfs4_file_put_fd(fp, O_RDWR);
193 } 200 }
194} 201}
195 202
@@ -3381,8 +3388,9 @@ static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to
3381 int i; 3388 int i;
3382 3389
3383 for (i = 1; i < 4; i++) { 3390 for (i = 1; i < 4; i++) {
3384 if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) { 3391 if (test_bit(i, &stp->st_access_bmap)
3385 nfs4_file_put_access(stp->st_file, i); 3392 && ((i & to_access) != i)) {
3393 nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(i));
3386 __clear_bit(i, &stp->st_access_bmap); 3394 __clear_bit(i, &stp->st_access_bmap);
3387 } 3395 }
3388 } 3396 }