Merge tag 'nfsd-4.10' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "The one new feature is support for a new NFSv4.2 mode_umask attribute that makes ACL inheritance a little more useful in environments that default to restrictive umasks. Requires client-side support, also on its way for 4.10. Other than that, miscellaneous smaller fixes and cleanup, especially to the server rdma code" [ The client side of the umask attribute was merged yesterday ] * tag 'nfsd-4.10' of git://linux-nfs.org/~bfields/linux: nfsd: add support for the umask attribute sunrpc: use DEFINE_SPINLOCK() svcrdma: Further clean-up of svc_rdma_get_inv_rkey() svcrdma: Break up dprintk format in svc_rdma_accept() svcrdma: Remove unused variable in rdma_copy_tail() svcrdma: Remove unused variables in xprt_rdma_bc_allocate() svcrdma: Remove svc_rdma_op_ctxt::wc_status svcrdma: Remove DMA map accounting svcrdma: Remove BH-disabled spin locking in svc_rdma_send() svcrdma: Renovate sendto chunk list parsing svcauth_gss: Close connection when dropping an incoming message svcrdma: Clear xpt_bc_xps in xprt_setup_rdma_bc() error exit arm nfsd: constify reply_cache_stats_operations structure nfsd: update workqueue creation sunrpc: GFP_KERNEL should be GFP_NOFS in crypto code nfsd: catch errors in decode_fattr earlier nfsd: clean up supported attribute handling nfsd: fix error handling for clients that fail to return the layout nfsd: more robust allocation failure handling in nfsd_reply_cache_init
此提交包含在:
@@ -1061,7 +1061,7 @@ static const struct rpc_call_ops nfsd4_cb_ops = {
|
||||
|
||||
int nfsd4_create_callback_queue(void)
|
||||
{
|
||||
callback_wq = create_singlethread_workqueue("nfsd4_callbacks");
|
||||
callback_wq = alloc_ordered_workqueue("nfsd4_callbacks", 0);
|
||||
if (!callback_wq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
|
@@ -686,10 +686,6 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
|
||||
return 0;
|
||||
}
|
||||
/* Fallthrough */
|
||||
case -NFS4ERR_NOMATCHING_LAYOUT:
|
||||
trace_layout_recall_done(&ls->ls_stid.sc_stateid);
|
||||
task->tk_status = 0;
|
||||
return 1;
|
||||
default:
|
||||
/*
|
||||
* Unknown error or non-responding client, we'll need to fence.
|
||||
@@ -702,6 +698,10 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
|
||||
else
|
||||
nfsd4_cb_layout_fail(ls);
|
||||
return -1;
|
||||
case -NFS4ERR_NOMATCHING_LAYOUT:
|
||||
trace_layout_recall_done(&ls->ls_stid.sc_stateid);
|
||||
task->tk_status = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -96,33 +96,15 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
{
|
||||
struct dentry *dentry = cstate->current_fh.fh_dentry;
|
||||
|
||||
/*
|
||||
* Check about attributes are supported by the NFSv4 server or not.
|
||||
* According to spec, unsupported attributes return ERR_ATTRNOTSUPP.
|
||||
*/
|
||||
if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) ||
|
||||
(bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) ||
|
||||
(bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
|
||||
if (!nfsd_attrs_supported(cstate->minorversion, bmval))
|
||||
return nfserr_attrnotsupp;
|
||||
|
||||
/*
|
||||
* Check FATTR4_WORD0_ACL can be supported
|
||||
* in current environment or not.
|
||||
*/
|
||||
if (bmval[0] & FATTR4_WORD0_ACL) {
|
||||
if (!IS_POSIXACL(d_inode(dentry)))
|
||||
return nfserr_attrnotsupp;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to spec, read-only attributes return ERR_INVAL.
|
||||
*/
|
||||
if (writable) {
|
||||
if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
|
||||
(bmval[2] & ~writable[2]))
|
||||
return nfserr_inval;
|
||||
}
|
||||
|
||||
if ((bmval[0] & FATTR4_WORD0_ACL) && !IS_POSIXACL(d_inode(dentry)))
|
||||
return nfserr_attrnotsupp;
|
||||
if (writable && !bmval_is_subset(bmval, writable))
|
||||
return nfserr_inval;
|
||||
if (writable && (bmval[2] & FATTR4_WORD2_MODE_UMASK) &&
|
||||
(bmval[1] & FATTR4_WORD1_MODE))
|
||||
return nfserr_inval;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
@@ -695,9 +677,9 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
||||
return nfserr_inval;
|
||||
|
||||
getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
|
||||
getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
|
||||
getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
|
||||
getattr->ga_bmval[0] &= nfsd_suppattrs[cstate->minorversion][0];
|
||||
getattr->ga_bmval[1] &= nfsd_suppattrs[cstate->minorversion][1];
|
||||
getattr->ga_bmval[2] &= nfsd_suppattrs[cstate->minorversion][2];
|
||||
|
||||
getattr->ga_fhp = &cstate->current_fh;
|
||||
return nfs_ok;
|
||||
@@ -799,9 +781,9 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
||||
return nfserr_inval;
|
||||
|
||||
readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
|
||||
readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
|
||||
readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
|
||||
readdir->rd_bmval[0] &= nfsd_suppattrs[cstate->minorversion][0];
|
||||
readdir->rd_bmval[1] &= nfsd_suppattrs[cstate->minorversion][1];
|
||||
readdir->rd_bmval[2] &= nfsd_suppattrs[cstate->minorversion][2];
|
||||
|
||||
if ((cookie == 1) || (cookie == 2) ||
|
||||
(cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
|
||||
|
@@ -33,6 +33,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/namei.h>
|
||||
@@ -57,6 +58,20 @@
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_XDR
|
||||
|
||||
u32 nfsd_suppattrs[3][3] = {
|
||||
{NFSD4_SUPPORTED_ATTRS_WORD0,
|
||||
NFSD4_SUPPORTED_ATTRS_WORD1,
|
||||
NFSD4_SUPPORTED_ATTRS_WORD2},
|
||||
|
||||
{NFSD4_1_SUPPORTED_ATTRS_WORD0,
|
||||
NFSD4_1_SUPPORTED_ATTRS_WORD1,
|
||||
NFSD4_1_SUPPORTED_ATTRS_WORD2},
|
||||
|
||||
{NFSD4_1_SUPPORTED_ATTRS_WORD0,
|
||||
NFSD4_1_SUPPORTED_ATTRS_WORD1,
|
||||
NFSD4_2_SUPPORTED_ATTRS_WORD2},
|
||||
};
|
||||
|
||||
/*
|
||||
* As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
|
||||
* directory in order to indicate to the client that a filesystem boundary is present
|
||||
@@ -285,7 +300,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
|
||||
static __be32
|
||||
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
||||
struct iattr *iattr, struct nfs4_acl **acl,
|
||||
struct xdr_netobj *label)
|
||||
struct xdr_netobj *label, int *umask)
|
||||
{
|
||||
int expected_len, len = 0;
|
||||
u32 dummy32;
|
||||
@@ -296,6 +311,14 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
||||
if ((status = nfsd4_decode_bitmap(argp, bmval)))
|
||||
return status;
|
||||
|
||||
if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
|
||||
|| bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
|
||||
|| bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) {
|
||||
if (nfsd_attrs_supported(argp->minorversion, bmval))
|
||||
return nfserr_inval;
|
||||
return nfserr_attrnotsupp;
|
||||
}
|
||||
|
||||
READ_BUF(4);
|
||||
expected_len = be32_to_cpup(p++);
|
||||
|
||||
@@ -435,12 +458,18 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
||||
return nfserr_jukebox;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
|
||||
|| bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
|
||||
|| bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
|
||||
READ_BUF(expected_len - len);
|
||||
else if (len != expected_len)
|
||||
if (bmval[2] & FATTR4_WORD2_MODE_UMASK) {
|
||||
if (!umask)
|
||||
goto xdr_error;
|
||||
READ_BUF(8);
|
||||
len += 8;
|
||||
dummy32 = be32_to_cpup(p++);
|
||||
iattr->ia_mode = dummy32 & (S_IFMT | S_IALLUGO);
|
||||
dummy32 = be32_to_cpup(p++);
|
||||
*umask = dummy32 & S_IRWXUGO;
|
||||
iattr->ia_valid |= ATTR_MODE;
|
||||
}
|
||||
if (len != expected_len)
|
||||
goto xdr_error;
|
||||
|
||||
DECODE_TAIL;
|
||||
@@ -634,7 +663,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
|
||||
return status;
|
||||
|
||||
status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
|
||||
&create->cr_acl, &create->cr_label);
|
||||
&create->cr_acl, &create->cr_label,
|
||||
¤t->fs->umask);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
@@ -879,13 +909,15 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
case NFS4_OPEN_NOCREATE:
|
||||
break;
|
||||
case NFS4_OPEN_CREATE:
|
||||
current->fs->umask = 0;
|
||||
READ_BUF(4);
|
||||
open->op_createmode = be32_to_cpup(p++);
|
||||
switch (open->op_createmode) {
|
||||
case NFS4_CREATE_UNCHECKED:
|
||||
case NFS4_CREATE_GUARDED:
|
||||
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||
&open->op_iattr, &open->op_acl, &open->op_label);
|
||||
&open->op_iattr, &open->op_acl, &open->op_label,
|
||||
¤t->fs->umask);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
@@ -899,7 +931,8 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
READ_BUF(NFS4_VERIFIER_SIZE);
|
||||
COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
|
||||
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||
&open->op_iattr, &open->op_acl, &open->op_label);
|
||||
&open->op_iattr, &open->op_acl, &open->op_label,
|
||||
¤t->fs->umask);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
@@ -1136,7 +1169,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
|
||||
if (status)
|
||||
return status;
|
||||
return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
|
||||
&setattr->sa_acl, &setattr->sa_label);
|
||||
&setattr->sa_acl, &setattr->sa_label, NULL);
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -2340,9 +2373,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
|
||||
BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
|
||||
BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
|
||||
BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion));
|
||||
BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
|
||||
BUG_ON(!nfsd_attrs_supported(minorversion, bmval));
|
||||
|
||||
if (exp->ex_fslocs.migrated) {
|
||||
status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
|
||||
@@ -2409,29 +2440,27 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
|
||||
p++; /* to be backfilled later */
|
||||
|
||||
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
|
||||
u32 word0 = nfsd_suppattrs0(minorversion);
|
||||
u32 word1 = nfsd_suppattrs1(minorversion);
|
||||
u32 word2 = nfsd_suppattrs2(minorversion);
|
||||
u32 *supp = nfsd_suppattrs[minorversion];
|
||||
|
||||
if (!IS_POSIXACL(dentry->d_inode))
|
||||
word0 &= ~FATTR4_WORD0_ACL;
|
||||
supp[0] &= ~FATTR4_WORD0_ACL;
|
||||
if (!contextsupport)
|
||||
word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
if (!word2) {
|
||||
supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
if (!supp[2]) {
|
||||
p = xdr_reserve_space(xdr, 12);
|
||||
if (!p)
|
||||
goto out_resource;
|
||||
*p++ = cpu_to_be32(2);
|
||||
*p++ = cpu_to_be32(word0);
|
||||
*p++ = cpu_to_be32(word1);
|
||||
*p++ = cpu_to_be32(supp[0]);
|
||||
*p++ = cpu_to_be32(supp[1]);
|
||||
} else {
|
||||
p = xdr_reserve_space(xdr, 16);
|
||||
if (!p)
|
||||
goto out_resource;
|
||||
*p++ = cpu_to_be32(3);
|
||||
*p++ = cpu_to_be32(word0);
|
||||
*p++ = cpu_to_be32(word1);
|
||||
*p++ = cpu_to_be32(word2);
|
||||
*p++ = cpu_to_be32(supp[0]);
|
||||
*p++ = cpu_to_be32(supp[1]);
|
||||
*p++ = cpu_to_be32(supp[2]);
|
||||
}
|
||||
}
|
||||
if (bmval0 & FATTR4_WORD0_TYPE) {
|
||||
|
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/log2.h>
|
||||
@@ -174,8 +175,12 @@ int nfsd_reply_cache_init(void)
|
||||
goto out_nomem;
|
||||
|
||||
drc_hashtbl = kcalloc(hashsize, sizeof(*drc_hashtbl), GFP_KERNEL);
|
||||
if (!drc_hashtbl)
|
||||
goto out_nomem;
|
||||
if (!drc_hashtbl) {
|
||||
drc_hashtbl = vzalloc(hashsize * sizeof(*drc_hashtbl));
|
||||
if (!drc_hashtbl)
|
||||
goto out_nomem;
|
||||
}
|
||||
|
||||
for (i = 0; i < hashsize; i++) {
|
||||
INIT_LIST_HEAD(&drc_hashtbl[i].lru_head);
|
||||
spin_lock_init(&drc_hashtbl[i].cache_lock);
|
||||
@@ -204,7 +209,7 @@ void nfsd_reply_cache_shutdown(void)
|
||||
}
|
||||
}
|
||||
|
||||
kfree (drc_hashtbl);
|
||||
kvfree(drc_hashtbl);
|
||||
drc_hashtbl = NULL;
|
||||
drc_hashsize = 0;
|
||||
|
||||
|
@@ -217,7 +217,7 @@ static const struct file_operations pool_stats_operations = {
|
||||
.release = nfsd_pool_stats_release,
|
||||
};
|
||||
|
||||
static struct file_operations reply_cache_stats_operations = {
|
||||
static const struct file_operations reply_cache_stats_operations = {
|
||||
.open = nfsd_reply_cache_stats_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
|
@@ -359,44 +359,46 @@ void nfsd_lockd_shutdown(void);
|
||||
|
||||
#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
|
||||
(NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
|
||||
FATTR4_WORD2_MODE_UMASK | \
|
||||
NFSD4_2_SECURITY_ATTRS)
|
||||
|
||||
static inline u32 nfsd_suppattrs0(u32 minorversion)
|
||||
extern u32 nfsd_suppattrs[3][3];
|
||||
|
||||
static inline bool bmval_is_subset(u32 *bm1, u32 *bm2)
|
||||
{
|
||||
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
|
||||
: NFSD4_SUPPORTED_ATTRS_WORD0;
|
||||
return !((bm1[0] & ~bm2[0]) ||
|
||||
(bm1[1] & ~bm2[1]) ||
|
||||
(bm1[2] & ~bm2[2]));
|
||||
}
|
||||
|
||||
static inline u32 nfsd_suppattrs1(u32 minorversion)
|
||||
static inline bool nfsd_attrs_supported(u32 minorversion, u32 *bmval)
|
||||
{
|
||||
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1
|
||||
: NFSD4_SUPPORTED_ATTRS_WORD1;
|
||||
}
|
||||
|
||||
static inline u32 nfsd_suppattrs2(u32 minorversion)
|
||||
{
|
||||
switch (minorversion) {
|
||||
default: return NFSD4_2_SUPPORTED_ATTRS_WORD2;
|
||||
case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2;
|
||||
case 0: return NFSD4_SUPPORTED_ATTRS_WORD2;
|
||||
}
|
||||
return bmval_is_subset(bmval, nfsd_suppattrs[minorversion]);
|
||||
}
|
||||
|
||||
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
|
||||
#define NFSD_WRITEONLY_ATTRS_WORD1 \
|
||||
(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
||||
|
||||
/* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
|
||||
/*
|
||||
* These are the only attrs allowed in CREATE/OPEN/SETATTR. Don't add
|
||||
* a writeable attribute here without also adding code to parse it to
|
||||
* nfsd4_decode_fattr().
|
||||
*/
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD0 \
|
||||
(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD1 \
|
||||
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
|
||||
| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
|
||||
#define MAYBE_FATTR4_WORD2_SECURITY_LABEL \
|
||||
FATTR4_WORD2_SECURITY_LABEL
|
||||
#else
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD2 0
|
||||
#define MAYBE_FATTR4_WORD2_SECURITY_LABEL 0
|
||||
#endif
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD2 \
|
||||
(FATTR4_WORD2_MODE_UMASK \
|
||||
| MAYBE_FATTR4_WORD2_SECURITY_LABEL)
|
||||
|
||||
#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
|
||||
NFSD_WRITEABLE_ATTRS_WORD0
|
||||
|
@@ -661,8 +661,8 @@ nfsd(void *vrqstp)
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
/* At this point, the thread shares current->fs
|
||||
* with the init process. We need to create files with a
|
||||
* umask of 0 instead of init's umask. */
|
||||
* with the init process. We need to create files with the
|
||||
* umask as defined by the client instead of init's umask. */
|
||||
if (unshare_fs_struct() < 0) {
|
||||
printk("Unable to start nfsd thread: out of memory\n");
|
||||
goto out;
|
||||
|
新增問題並參考
封鎖使用者