diff options
author | Eryu Guan <eguan@redhat.com> | 2017-09-29 03:01:10 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-10-05 14:45:25 -0400 |
commit | ec572b9e81b1df79147c2e6f69458e65cf248598 (patch) | |
tree | 57513221ff79e7be5329d2c8f227198431462877 | |
parent | 7d34cd12061d2cf38f7505c0ab2ae2f03fbe8e08 (diff) |
nfsd4: define nfsd4_secinfo_no_name_release()
Commit 34b1744c91cc ("nfsd4: define ->op_release for compound ops")
defined a couple ->op_release functions and run them if necessary.
But there's a problem with that is that it reused
nfsd4_secinfo_release() as the op_release of OP_SECINFO_NO_NAME, and
caused a leak on struct nfsd4_secinfo_no_name in
nfsd4_encode_secinfo_no_name(), because there's no .si_exp field in
struct nfsd4_secinfo_no_name.
I found this because I was unable to umount an ext4 partition after
exporting it via NFS & run fsstress on the nfs mount. A simplified
reproducer would be:
# mount a local-fs device at /mnt/test, and export it via NFS with
# fsid=0 export option (this is required)
mount /dev/sda5 /mnt/test
echo "/mnt/test *(rw,no_root_squash,fsid=0)" >> /etc/exports
service nfs restart
# locally mount the nfs export with all default, note that I have
# nfsv4.1 configured as the default nfs version, because of the
# fsid export option, v4 mount would fail and fall back to v3
mount localhost:/mnt/test /mnt/nfs
# try to umount the underlying device, but got EBUSY
umount /mnt/nfs
service nfs stop
umount /mnt/test <=== EBUSY here
Fixed it by defining a separate nfsd4_secinfo_no_name_release()
function as the op_release method of OP_SECINFO_NO_NAME that
releases the correct nfsd4_secinfo_no_name structure.
Fixes: 34b1744c91cc ("nfsd4: define ->op_release for compound ops")
Signed-off-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/nfsd/nfs4proc.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3c69db7d4905..8487486ec496 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -927,6 +927,13 @@ nfsd4_secinfo_release(union nfsd4_op_u *u) | |||
927 | exp_put(u->secinfo.si_exp); | 927 | exp_put(u->secinfo.si_exp); |
928 | } | 928 | } |
929 | 929 | ||
930 | static void | ||
931 | nfsd4_secinfo_no_name_release(union nfsd4_op_u *u) | ||
932 | { | ||
933 | if (u->secinfo_no_name.sin_exp) | ||
934 | exp_put(u->secinfo_no_name.sin_exp); | ||
935 | } | ||
936 | |||
930 | static __be32 | 937 | static __be32 |
931 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 938 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
932 | union nfsd4_op_u *u) | 939 | union nfsd4_op_u *u) |
@@ -2375,7 +2382,7 @@ static const struct nfsd4_operation nfsd4_ops[] = { | |||
2375 | }, | 2382 | }, |
2376 | [OP_SECINFO_NO_NAME] = { | 2383 | [OP_SECINFO_NO_NAME] = { |
2377 | .op_func = nfsd4_secinfo_no_name, | 2384 | .op_func = nfsd4_secinfo_no_name, |
2378 | .op_release = nfsd4_secinfo_release, | 2385 | .op_release = nfsd4_secinfo_no_name_release, |
2379 | .op_flags = OP_HANDLES_WRONGSEC, | 2386 | .op_flags = OP_HANDLES_WRONGSEC, |
2380 | .op_name = "OP_SECINFO_NO_NAME", | 2387 | .op_name = "OP_SECINFO_NO_NAME", |
2381 | .op_rsize_bop = nfsd4_secinfo_rsize, | 2388 | .op_rsize_bop = nfsd4_secinfo_rsize, |