]>
Commit | Line | Data |
---|---|---|
0d1514e0 GKH |
1 | From f197c27196a5e7631b89e2e92daa096fcf7c302c Mon Sep 17 00:00:00 2001 |
2 | From: "J. Bruce Fields" <bfields@redhat.com> | |
3 | Date: Wed, 29 Jun 2011 08:23:50 -0400 | |
4 | Subject: nfsd4: fix file leak on open_downgrade | |
5 | ||
6 | From: "J. Bruce Fields" <bfields@redhat.com> | |
7 | ||
8 | commit f197c27196a5e7631b89e2e92daa096fcf7c302c upstream. | |
9 | ||
10 | Stateid's hold a read reference for a read open, a write reference for a | |
11 | write open, and an additional one of each for each read+write open. The | |
12 | latter wasn't getting put on a downgrade, so something like: | |
13 | ||
14 | open RW | |
15 | open R | |
16 | downgrade to R | |
17 | ||
18 | was resulting in a file leak. | |
19 | ||
20 | Also fix an imbalance in an error path. | |
21 | ||
22 | Regression from 7d94784293096c0a46897acdb83be5abd9278ece "nfsd4: fix | |
23 | downgrade/lock logic". | |
24 | ||
25 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
26 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
27 | ||
28 | --- | |
29 | fs/nfsd/nfs4state.c | 31 ++++++++----------------------- | |
30 | 1 file changed, 8 insertions(+), 23 deletions(-) | |
31 | ||
32 | --- a/fs/nfsd/nfs4state.c | |
33 | +++ b/fs/nfsd/nfs4state.c | |
34 | @@ -2332,15 +2332,6 @@ out: | |
35 | return ret; | |
36 | } | |
37 | ||
38 | -static inline void | |
39 | -nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) | |
40 | -{ | |
41 | - if (share_access & NFS4_SHARE_ACCESS_WRITE) | |
42 | - nfs4_file_put_access(fp, O_WRONLY); | |
43 | - if (share_access & NFS4_SHARE_ACCESS_READ) | |
44 | - nfs4_file_put_access(fp, O_RDONLY); | |
45 | -} | |
46 | - | |
47 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) | |
48 | { | |
49 | /* We're assuming the state code never drops its reference | |
50 | @@ -2627,7 +2618,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp | |
51 | status = nfsd4_truncate(rqstp, cur_fh, open); | |
52 | if (status) { | |
53 | if (new_access) { | |
54 | - int oflag = nfs4_access_to_omode(new_access); | |
55 | + int oflag = nfs4_access_to_omode(op_share_access); | |
56 | nfs4_file_put_access(fp, oflag); | |
57 | } | |
58 | return status; | |
59 | @@ -3385,18 +3376,15 @@ out: | |
60 | return status; | |
61 | } | |
62 | ||
63 | - | |
64 | -/* | |
65 | - * unset all bits in union bitmap (bmap) that | |
66 | - * do not exist in share (from successful OPEN_DOWNGRADE) | |
67 | - */ | |
68 | -static void | |
69 | -reset_union_bmap_access(unsigned long access, unsigned long *bmap) | |
70 | +static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access) | |
71 | { | |
72 | int i; | |
73 | + | |
74 | for (i = 1; i < 4; i++) { | |
75 | - if ((i & access) != i) | |
76 | - __clear_bit(i, bmap); | |
77 | + if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) { | |
78 | + nfs4_file_put_access(stp->st_file, i); | |
79 | + __clear_bit(i, &stp->st_access_bmap); | |
80 | + } | |
81 | } | |
82 | } | |
83 | ||
84 | @@ -3417,7 +3405,6 @@ nfsd4_open_downgrade(struct svc_rqst *rq | |
85 | { | |
86 | __be32 status; | |
87 | struct nfs4_stateid *stp; | |
88 | - unsigned int share_access; | |
89 | ||
90 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", | |
91 | (int)cstate->current_fh.fh_dentry->d_name.len, | |
92 | @@ -3446,10 +3433,8 @@ nfsd4_open_downgrade(struct svc_rqst *rq | |
93 | stp->st_deny_bmap, od->od_share_deny); | |
94 | goto out; | |
95 | } | |
96 | - set_access(&share_access, stp->st_access_bmap); | |
97 | - nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); | |
98 | + nfs4_file_downgrade(stp, od->od_share_access); | |
99 | ||
100 | - reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); | |
101 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | |
102 | ||
103 | update_stateid(&stp->st_stateid); |