diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/acl.h | 10 | ||||
-rw-r--r-- | fs/nfsd/nfs4acl.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 19 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 39 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 28 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 30 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 2 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.h | 14 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 15 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 2 |
12 files changed, 129 insertions, 50 deletions
diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h index a812fd1b92a4..b481e1f5eecc 100644 --- a/fs/nfsd/acl.h +++ b/fs/nfsd/acl.h | |||
@@ -39,9 +39,13 @@ struct nfs4_acl; | |||
39 | struct svc_fh; | 39 | struct svc_fh; |
40 | struct svc_rqst; | 40 | struct svc_rqst; |
41 | 41 | ||
42 | /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to | 42 | /* |
43 | * fit in a page: */ | 43 | * Maximum ACL we'll accept from a client; chosen (somewhat |
44 | #define NFS4_ACL_MAX 170 | 44 | * arbitrarily) so that kmalloc'ing the ACL shouldn't require a |
45 | * high-order allocation. This allows 204 ACEs on x86_64: | ||
46 | */ | ||
47 | #define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \ | ||
48 | / sizeof(struct nfs4_ace)) | ||
45 | 49 | ||
46 | struct nfs4_acl *nfs4_acl_new(int); | 50 | struct nfs4_acl *nfs4_acl_new(int); |
47 | int nfs4_acl_get_whotype(char *, u32); | 51 | int nfs4_acl_get_whotype(char *, u32); |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index d190e33d0ec2..6f3f392d48af 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -542,7 +542,10 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
542 | * up setting a 3-element effective posix ACL with all | 542 | * up setting a 3-element effective posix ACL with all |
543 | * permissions zero. | 543 | * permissions zero. |
544 | */ | 544 | */ |
545 | nace = 4 + state->users->n + state->groups->n; | 545 | if (!state->users->n && !state->groups->n) |
546 | nace = 3; | ||
547 | else /* Note we also include a MASK ACE in this case: */ | ||
548 | nace = 4 + state->users->n + state->groups->n; | ||
546 | pacl = posix_acl_alloc(nace, GFP_KERNEL); | 549 | pacl = posix_acl_alloc(nace, GFP_KERNEL); |
547 | if (!pacl) | 550 | if (!pacl) |
548 | return ERR_PTR(-ENOMEM); | 551 | return ERR_PTR(-ENOMEM); |
@@ -586,9 +589,11 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
586 | add_to_mask(state, &state->groups->aces[i].perms); | 589 | add_to_mask(state, &state->groups->aces[i].perms); |
587 | } | 590 | } |
588 | 591 | ||
589 | pace++; | 592 | if (!state->users->n && !state->groups->n) { |
590 | pace->e_tag = ACL_MASK; | 593 | pace++; |
591 | low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); | 594 | pace->e_tag = ACL_MASK; |
595 | low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); | ||
596 | } | ||
592 | 597 | ||
593 | pace++; | 598 | pace++; |
594 | pace->e_tag = ACL_OTHER; | 599 | pace->e_tag = ACL_OTHER; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 7f05cd140de3..39c8ef875f91 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -32,6 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/sunrpc/clnt.h> | 34 | #include <linux/sunrpc/clnt.h> |
35 | #include <linux/sunrpc/xprt.h> | ||
35 | #include <linux/sunrpc/svc_xprt.h> | 36 | #include <linux/sunrpc/svc_xprt.h> |
36 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
37 | #include "nfsd.h" | 38 | #include "nfsd.h" |
@@ -635,6 +636,22 @@ static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc | |||
635 | } | 636 | } |
636 | } | 637 | } |
637 | 638 | ||
639 | static struct rpc_clnt *create_backchannel_client(struct rpc_create_args *args) | ||
640 | { | ||
641 | struct rpc_xprt *xprt; | ||
642 | |||
643 | if (args->protocol != XPRT_TRANSPORT_BC_TCP) | ||
644 | return rpc_create(args); | ||
645 | |||
646 | xprt = args->bc_xprt->xpt_bc_xprt; | ||
647 | if (xprt) { | ||
648 | xprt_get(xprt); | ||
649 | return rpc_create_xprt(args, xprt); | ||
650 | } | ||
651 | |||
652 | return rpc_create(args); | ||
653 | } | ||
654 | |||
638 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) | 655 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) |
639 | { | 656 | { |
640 | struct rpc_timeout timeparms = { | 657 | struct rpc_timeout timeparms = { |
@@ -674,7 +691,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
674 | args.authflavor = ses->se_cb_sec.flavor; | 691 | args.authflavor = ses->se_cb_sec.flavor; |
675 | } | 692 | } |
676 | /* Create RPC client */ | 693 | /* Create RPC client */ |
677 | client = rpc_create(&args); | 694 | client = create_backchannel_client(&args); |
678 | if (IS_ERR(client)) { | 695 | if (IS_ERR(client)) { |
679 | dprintk("NFSD: couldn't create callback client: %ld\n", | 696 | dprintk("NFSD: couldn't create callback client: %ld\n", |
680 | PTR_ERR(client)); | 697 | PTR_ERR(client)); |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 82189b208af3..d543222babf3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -1273,6 +1273,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1273 | struct nfsd4_op *op; | 1273 | struct nfsd4_op *op; |
1274 | struct nfsd4_operation *opdesc; | 1274 | struct nfsd4_operation *opdesc; |
1275 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1275 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1276 | struct svc_fh *current_fh = &cstate->current_fh; | ||
1277 | struct svc_fh *save_fh = &cstate->save_fh; | ||
1276 | int slack_bytes; | 1278 | int slack_bytes; |
1277 | u32 plen = 0; | 1279 | u32 plen = 0; |
1278 | __be32 status; | 1280 | __be32 status; |
@@ -1288,11 +1290,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1288 | resp->tag = args->tag; | 1290 | resp->tag = args->tag; |
1289 | resp->opcnt = 0; | 1291 | resp->opcnt = 0; |
1290 | resp->rqstp = rqstp; | 1292 | resp->rqstp = rqstp; |
1291 | resp->cstate.minorversion = args->minorversion; | 1293 | cstate->minorversion = args->minorversion; |
1292 | resp->cstate.replay_owner = NULL; | 1294 | cstate->replay_owner = NULL; |
1293 | resp->cstate.session = NULL; | 1295 | cstate->session = NULL; |
1294 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); | 1296 | fh_init(current_fh, NFS4_FHSIZE); |
1295 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); | 1297 | fh_init(save_fh, NFS4_FHSIZE); |
1296 | /* | 1298 | /* |
1297 | * Don't use the deferral mechanism for NFSv4; compounds make it | 1299 | * Don't use the deferral mechanism for NFSv4; compounds make it |
1298 | * too hard to avoid non-idempotency problems. | 1300 | * too hard to avoid non-idempotency problems. |
@@ -1345,20 +1347,28 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1345 | 1347 | ||
1346 | opdesc = OPDESC(op); | 1348 | opdesc = OPDESC(op); |
1347 | 1349 | ||
1348 | if (!cstate->current_fh.fh_dentry) { | 1350 | if (!current_fh->fh_dentry) { |
1349 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { | 1351 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { |
1350 | op->status = nfserr_nofilehandle; | 1352 | op->status = nfserr_nofilehandle; |
1351 | goto encode_op; | 1353 | goto encode_op; |
1352 | } | 1354 | } |
1353 | } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && | 1355 | } else if (current_fh->fh_export->ex_fslocs.migrated && |
1354 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { | 1356 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { |
1355 | op->status = nfserr_moved; | 1357 | op->status = nfserr_moved; |
1356 | goto encode_op; | 1358 | goto encode_op; |
1357 | } | 1359 | } |
1358 | 1360 | ||
1361 | fh_clear_wcc(current_fh); | ||
1362 | |||
1359 | /* If op is non-idempotent */ | 1363 | /* If op is non-idempotent */ |
1360 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { | 1364 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { |
1361 | plen = opdesc->op_rsize_bop(rqstp, op); | 1365 | plen = opdesc->op_rsize_bop(rqstp, op); |
1366 | /* | ||
1367 | * If there's still another operation, make sure | ||
1368 | * we'll have space to at least encode an error: | ||
1369 | */ | ||
1370 | if (resp->opcnt < args->opcnt) | ||
1371 | plen += COMPOUND_ERR_SLACK_SPACE; | ||
1362 | op->status = nfsd4_check_resp_size(resp, plen); | 1372 | op->status = nfsd4_check_resp_size(resp, plen); |
1363 | } | 1373 | } |
1364 | 1374 | ||
@@ -1377,12 +1387,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1377 | clear_current_stateid(cstate); | 1387 | clear_current_stateid(cstate); |
1378 | 1388 | ||
1379 | if (need_wrongsec_check(rqstp)) | 1389 | if (need_wrongsec_check(rqstp)) |
1380 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | 1390 | op->status = check_nfsd_access(current_fh->fh_export, rqstp); |
1381 | } | 1391 | } |
1382 | 1392 | ||
1383 | encode_op: | 1393 | encode_op: |
1384 | /* Only from SEQUENCE */ | 1394 | /* Only from SEQUENCE */ |
1385 | if (resp->cstate.status == nfserr_replay_cache) { | 1395 | if (cstate->status == nfserr_replay_cache) { |
1386 | dprintk("%s NFS4.1 replay from cache\n", __func__); | 1396 | dprintk("%s NFS4.1 replay from cache\n", __func__); |
1387 | status = op->status; | 1397 | status = op->status; |
1388 | goto out; | 1398 | goto out; |
@@ -1411,10 +1421,10 @@ encode_op: | |||
1411 | nfsd4_increment_op_stats(op->opnum); | 1421 | nfsd4_increment_op_stats(op->opnum); |
1412 | } | 1422 | } |
1413 | 1423 | ||
1414 | resp->cstate.status = status; | 1424 | cstate->status = status; |
1415 | fh_put(&resp->cstate.current_fh); | 1425 | fh_put(current_fh); |
1416 | fh_put(&resp->cstate.save_fh); | 1426 | fh_put(save_fh); |
1417 | BUG_ON(resp->cstate.replay_owner); | 1427 | BUG_ON(cstate->replay_owner); |
1418 | out: | 1428 | out: |
1419 | /* Reset deferral mechanism for RPC deferrals */ | 1429 | /* Reset deferral mechanism for RPC deferrals */ |
1420 | rqstp->rq_usedeferral = 1; | 1430 | rqstp->rq_usedeferral = 1; |
@@ -1523,7 +1533,8 @@ static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *o | |||
1523 | 1533 | ||
1524 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1534 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1525 | { | 1535 | { |
1526 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); | 1536 | return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) * |
1537 | sizeof(__be32); | ||
1527 | } | 1538 | } |
1528 | 1539 | ||
1529 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1540 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d5d070fbeb35..3ba65979a3cd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1538,7 +1538,7 @@ out_err: | |||
1538 | } | 1538 | } |
1539 | 1539 | ||
1540 | /* | 1540 | /* |
1541 | * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size. | 1541 | * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. |
1542 | */ | 1542 | */ |
1543 | void | 1543 | void |
1544 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | 1544 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) |
@@ -1596,7 +1596,7 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, | |||
1596 | * The sequence operation is not cached because we can use the slot and | 1596 | * The sequence operation is not cached because we can use the slot and |
1597 | * session values. | 1597 | * session values. |
1598 | */ | 1598 | */ |
1599 | __be32 | 1599 | static __be32 |
1600 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | 1600 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, |
1601 | struct nfsd4_sequence *seq) | 1601 | struct nfsd4_sequence *seq) |
1602 | { | 1602 | { |
@@ -1605,9 +1605,8 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
1605 | 1605 | ||
1606 | dprintk("--> %s slot %p\n", __func__, slot); | 1606 | dprintk("--> %s slot %p\n", __func__, slot); |
1607 | 1607 | ||
1608 | /* Either returns 0 or nfserr_retry_uncached */ | ||
1609 | status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); | 1608 | status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); |
1610 | if (status == nfserr_retry_uncached_rep) | 1609 | if (status) |
1611 | return status; | 1610 | return status; |
1612 | 1611 | ||
1613 | /* The sequence operation has been encoded, cstate->datap set. */ | 1612 | /* The sequence operation has been encoded, cstate->datap set. */ |
@@ -2287,7 +2286,8 @@ out: | |||
2287 | if (!list_empty(&clp->cl_revoked)) | 2286 | if (!list_empty(&clp->cl_revoked)) |
2288 | seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; | 2287 | seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; |
2289 | out_no_session: | 2288 | out_no_session: |
2290 | kfree(conn); | 2289 | if (conn) |
2290 | free_conn(conn); | ||
2291 | spin_unlock(&nn->client_lock); | 2291 | spin_unlock(&nn->client_lock); |
2292 | return status; | 2292 | return status; |
2293 | out_put_session: | 2293 | out_put_session: |
@@ -3627,8 +3627,11 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, | |||
3627 | return nfserr_bad_stateid; | 3627 | return nfserr_bad_stateid; |
3628 | status = lookup_clientid(&stateid->si_opaque.so_clid, sessions, | 3628 | status = lookup_clientid(&stateid->si_opaque.so_clid, sessions, |
3629 | nn, &cl); | 3629 | nn, &cl); |
3630 | if (status == nfserr_stale_clientid) | 3630 | if (status == nfserr_stale_clientid) { |
3631 | if (sessions) | ||
3632 | return nfserr_bad_stateid; | ||
3631 | return nfserr_stale_stateid; | 3633 | return nfserr_stale_stateid; |
3634 | } | ||
3632 | if (status) | 3635 | if (status) |
3633 | return status; | 3636 | return status; |
3634 | *s = find_stateid_by_type(cl, stateid, typemask); | 3637 | *s = find_stateid_by_type(cl, stateid, typemask); |
@@ -5062,7 +5065,6 @@ nfs4_state_destroy_net(struct net *net) | |||
5062 | int i; | 5065 | int i; |
5063 | struct nfs4_client *clp = NULL; | 5066 | struct nfs4_client *clp = NULL; |
5064 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 5067 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
5065 | struct rb_node *node, *tmp; | ||
5066 | 5068 | ||
5067 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 5069 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
5068 | while (!list_empty(&nn->conf_id_hashtbl[i])) { | 5070 | while (!list_empty(&nn->conf_id_hashtbl[i])) { |
@@ -5071,13 +5073,11 @@ nfs4_state_destroy_net(struct net *net) | |||
5071 | } | 5073 | } |
5072 | } | 5074 | } |
5073 | 5075 | ||
5074 | node = rb_first(&nn->unconf_name_tree); | 5076 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
5075 | while (node != NULL) { | 5077 | while (!list_empty(&nn->unconf_id_hashtbl[i])) { |
5076 | tmp = node; | 5078 | clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); |
5077 | node = rb_next(tmp); | 5079 | destroy_client(clp); |
5078 | clp = rb_entry(tmp, struct nfs4_client, cl_namenode); | 5080 | } |
5079 | rb_erase(tmp, &nn->unconf_name_tree); | ||
5080 | destroy_client(clp); | ||
5081 | } | 5081 | } |
5082 | 5082 | ||
5083 | kfree(nn->sessionid_hashtbl); | 5083 | kfree(nn->sessionid_hashtbl); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 63f2395c57ed..2723c1badd01 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -294,7 +294,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
294 | READ32(nace); | 294 | READ32(nace); |
295 | 295 | ||
296 | if (nace > NFS4_ACL_MAX) | 296 | if (nace > NFS4_ACL_MAX) |
297 | return nfserr_resource; | 297 | return nfserr_fbig; |
298 | 298 | ||
299 | *acl = nfs4_acl_new(nace); | 299 | *acl = nfs4_acl_new(nace); |
300 | if (*acl == NULL) | 300 | if (*acl == NULL) |
@@ -1222,7 +1222,6 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) | |||
1222 | } | 1222 | } |
1223 | write->wr_head.iov_base = p; | 1223 | write->wr_head.iov_base = p; |
1224 | write->wr_head.iov_len = avail; | 1224 | write->wr_head.iov_len = avail; |
1225 | WARN_ON(avail != (XDR_QUADLEN(avail) << 2)); | ||
1226 | write->wr_pagelist = argp->pagelist; | 1225 | write->wr_pagelist = argp->pagelist; |
1227 | 1226 | ||
1228 | len = XDR_QUADLEN(write->wr_buflen) << 2; | 1227 | len = XDR_QUADLEN(write->wr_buflen) << 2; |
@@ -2483,6 +2482,8 @@ out_acl: | |||
2483 | goto out; | 2482 | goto out; |
2484 | } | 2483 | } |
2485 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2484 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
2485 | if ((buflen -= 16) < 0) | ||
2486 | goto out_resource; | ||
2486 | WRITE32(3); | 2487 | WRITE32(3); |
2487 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); | 2488 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); |
2488 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1); | 2489 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1); |
@@ -2499,8 +2500,10 @@ out: | |||
2499 | security_release_secctx(context, contextlen); | 2500 | security_release_secctx(context, contextlen); |
2500 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | 2501 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ |
2501 | kfree(acl); | 2502 | kfree(acl); |
2502 | if (tempfh) | 2503 | if (tempfh) { |
2503 | fh_put(tempfh); | 2504 | fh_put(tempfh); |
2505 | kfree(tempfh); | ||
2506 | } | ||
2504 | return status; | 2507 | return status; |
2505 | out_nfserr: | 2508 | out_nfserr: |
2506 | status = nfserrno(err); | 2509 | status = nfserrno(err); |
@@ -3471,6 +3474,9 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
3471 | struct nfsd4_test_stateid_id *stateid, *next; | 3474 | struct nfsd4_test_stateid_id *stateid, *next; |
3472 | __be32 *p; | 3475 | __be32 *p; |
3473 | 3476 | ||
3477 | if (nfserr) | ||
3478 | return nfserr; | ||
3479 | |||
3474 | RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids)); | 3480 | RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids)); |
3475 | *p++ = htonl(test_stateid->ts_num_ids); | 3481 | *p++ = htonl(test_stateid->ts_num_ids); |
3476 | 3482 | ||
@@ -3579,8 +3585,6 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) | |||
3579 | return 0; | 3585 | return 0; |
3580 | 3586 | ||
3581 | session = resp->cstate.session; | 3587 | session = resp->cstate.session; |
3582 | if (session == NULL) | ||
3583 | return 0; | ||
3584 | 3588 | ||
3585 | if (xb->page_len == 0) { | 3589 | if (xb->page_len == 0) { |
3586 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; | 3590 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; |
@@ -3620,9 +3624,17 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3620 | BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || | 3624 | BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || |
3621 | !nfsd4_enc_ops[op->opnum]); | 3625 | !nfsd4_enc_ops[op->opnum]); |
3622 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); | 3626 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); |
3623 | /* nfsd4_check_drc_limit guarantees enough room for error status */ | 3627 | /* nfsd4_check_resp_size guarantees enough room for error status */ |
3624 | if (!op->status) | 3628 | if (!op->status) |
3625 | op->status = nfsd4_check_resp_size(resp, 0); | 3629 | op->status = nfsd4_check_resp_size(resp, 0); |
3630 | if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) { | ||
3631 | struct nfsd4_slot *slot = resp->cstate.slot; | ||
3632 | |||
3633 | if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) | ||
3634 | op->status = nfserr_rep_too_big_to_cache; | ||
3635 | else | ||
3636 | op->status = nfserr_rep_too_big; | ||
3637 | } | ||
3626 | if (so) { | 3638 | if (so) { |
3627 | so->so_replay.rp_status = op->status; | 3639 | so->so_replay.rp_status = op->status; |
3628 | so->so_replay.rp_buflen = (char *)resp->p - (char *)(statp+1); | 3640 | so->so_replay.rp_buflen = (char *)resp->p - (char *)(statp+1); |
@@ -3691,6 +3703,12 @@ int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp) | |||
3691 | int | 3703 | int |
3692 | nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) | 3704 | nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) |
3693 | { | 3705 | { |
3706 | if (rqstp->rq_arg.head[0].iov_len % 4) { | ||
3707 | /* client is nuts */ | ||
3708 | dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)", | ||
3709 | __func__, svc_addr(rqstp), be32_to_cpu(rqstp->rq_xid)); | ||
3710 | return 0; | ||
3711 | } | ||
3694 | args->p = p; | 3712 | args->p = p; |
3695 | args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; | 3713 | args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; |
3696 | args->pagelist = rqstp->rq_arg.pages; | 3714 | args->pagelist = rqstp->rq_arg.pages; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7f555179bf81..f34d9de802ab 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -699,6 +699,11 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net) | |||
699 | if (err != 0 || fd < 0) | 699 | if (err != 0 || fd < 0) |
700 | return -EINVAL; | 700 | return -EINVAL; |
701 | 701 | ||
702 | if (svc_alien_sock(net, fd)) { | ||
703 | printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__); | ||
704 | return -EINVAL; | ||
705 | } | ||
706 | |||
702 | err = nfsd_create_serv(net); | 707 | err = nfsd_create_serv(net); |
703 | if (err != 0) | 708 | if (err != 0) |
704 | return err; | 709 | return err; |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 30f34ab02137..479eb681c27c 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -282,7 +282,7 @@ void nfsd_lockd_shutdown(void); | |||
282 | * reason. | 282 | * reason. |
283 | */ | 283 | */ |
284 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ | 284 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ |
285 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ | 285 | #define COMPOUND_ERR_SLACK_SPACE 16 /* OP_SETATTR */ |
286 | 286 | ||
287 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ | 287 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ |
288 | 288 | ||
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 4775bc4896c8..ad67964d0bb1 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h | |||
@@ -133,6 +133,17 @@ fh_init(struct svc_fh *fhp, int maxsize) | |||
133 | 133 | ||
134 | #ifdef CONFIG_NFSD_V3 | 134 | #ifdef CONFIG_NFSD_V3 |
135 | /* | 135 | /* |
136 | * The wcc data stored in current_fh should be cleared | ||
137 | * between compound ops. | ||
138 | */ | ||
139 | static inline void | ||
140 | fh_clear_wcc(struct svc_fh *fhp) | ||
141 | { | ||
142 | fhp->fh_post_saved = 0; | ||
143 | fhp->fh_pre_saved = 0; | ||
144 | } | ||
145 | |||
146 | /* | ||
136 | * Fill in the pre_op attr for the wcc data | 147 | * Fill in the pre_op attr for the wcc data |
137 | */ | 148 | */ |
138 | static inline void | 149 | static inline void |
@@ -152,7 +163,8 @@ fill_pre_wcc(struct svc_fh *fhp) | |||
152 | 163 | ||
153 | extern void fill_post_wcc(struct svc_fh *); | 164 | extern void fill_post_wcc(struct svc_fh *); |
154 | #else | 165 | #else |
155 | #define fill_pre_wcc(ignored) | 166 | #define fh_clear_wcc(ignored) |
167 | #define fill_pre_wcc(ignored) | ||
156 | #define fill_post_wcc(notused) | 168 | #define fill_post_wcc(notused) |
157 | #endif /* CONFIG_NFSD_V3 */ | 169 | #endif /* CONFIG_NFSD_V3 */ |
158 | 170 | ||
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index b17d93214d01..9c769a47ac5a 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -152,7 +152,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, | |||
152 | type = (stat->mode & S_IFMT); | 152 | type = (stat->mode & S_IFMT); |
153 | 153 | ||
154 | *p++ = htonl(nfs_ftypes[type >> 12]); | 154 | *p++ = htonl(nfs_ftypes[type >> 12]); |
155 | *p++ = htonl((u32) (stat->mode & S_IALLUGO)); | 155 | *p++ = htonl((u32) stat->mode); |
156 | *p++ = htonl((u32) stat->nlink); | 156 | *p++ = htonl((u32) stat->nlink); |
157 | *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid)); | 157 | *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid)); |
158 | *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid)); | 158 | *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid)); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 915808b36df7..16f0673a423c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -404,6 +404,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
404 | umode_t ftype = 0; | 404 | umode_t ftype = 0; |
405 | __be32 err; | 405 | __be32 err; |
406 | int host_err; | 406 | int host_err; |
407 | bool get_write_count; | ||
407 | int size_change = 0; | 408 | int size_change = 0; |
408 | 409 | ||
409 | if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) | 410 | if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) |
@@ -411,10 +412,18 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
411 | if (iap->ia_valid & ATTR_SIZE) | 412 | if (iap->ia_valid & ATTR_SIZE) |
412 | ftype = S_IFREG; | 413 | ftype = S_IFREG; |
413 | 414 | ||
415 | /* Callers that do fh_verify should do the fh_want_write: */ | ||
416 | get_write_count = !fhp->fh_dentry; | ||
417 | |||
414 | /* Get inode */ | 418 | /* Get inode */ |
415 | err = fh_verify(rqstp, fhp, ftype, accmode); | 419 | err = fh_verify(rqstp, fhp, ftype, accmode); |
416 | if (err) | 420 | if (err) |
417 | goto out; | 421 | goto out; |
422 | if (get_write_count) { | ||
423 | host_err = fh_want_write(fhp); | ||
424 | if (host_err) | ||
425 | return nfserrno(host_err); | ||
426 | } | ||
418 | 427 | ||
419 | dentry = fhp->fh_dentry; | 428 | dentry = fhp->fh_dentry; |
420 | inode = dentry->d_inode; | 429 | inode = dentry->d_inode; |
@@ -1706,10 +1715,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1706 | dput(odentry); | 1715 | dput(odentry); |
1707 | out_nfserr: | 1716 | out_nfserr: |
1708 | err = nfserrno(host_err); | 1717 | err = nfserrno(host_err); |
1709 | 1718 | /* | |
1710 | /* we cannot reply on fh_unlock on the two filehandles, | 1719 | * We cannot rely on fh_unlock on the two filehandles, |
1711 | * as that would do the wrong thing if the two directories | 1720 | * as that would do the wrong thing if the two directories |
1712 | * were the same, so again we do it by hand | 1721 | * were the same, so again we do it by hand. |
1713 | */ | 1722 | */ |
1714 | fill_post_wcc(ffhp); | 1723 | fill_post_wcc(ffhp); |
1715 | fill_post_wcc(tfhp); | 1724 | fill_post_wcc(tfhp); |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index d278a0d03496..5ea7df305083 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -574,8 +574,6 @@ extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
574 | struct nfsd4_compound_state *, | 574 | struct nfsd4_compound_state *, |
575 | struct nfsd4_setclientid_confirm *setclientid_confirm); | 575 | struct nfsd4_setclientid_confirm *setclientid_confirm); |
576 | extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp); | 576 | extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp); |
577 | extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | ||
578 | struct nfsd4_sequence *seq); | ||
579 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, | 577 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, |
580 | struct nfsd4_compound_state *, struct nfsd4_exchange_id *); | 578 | struct nfsd4_compound_state *, struct nfsd4_exchange_id *); |
581 | extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *); | 579 | extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *); |