diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/Kconfig | 16 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 48 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 20 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 235 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 174 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 27 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 13 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 42 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 7 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 4 |
11 files changed, 458 insertions, 129 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 430b6872806f..dc8f1ef665ce 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig | |||
@@ -81,6 +81,22 @@ config NFSD_V4 | |||
81 | 81 | ||
82 | If unsure, say N. | 82 | If unsure, say N. |
83 | 83 | ||
84 | config NFSD_V4_SECURITY_LABEL | ||
85 | bool "Provide Security Label support for NFSv4 server" | ||
86 | depends on NFSD_V4 && SECURITY | ||
87 | help | ||
88 | |||
89 | Say Y here if you want enable fine-grained security label attribute | ||
90 | support for NFS version 4. Security labels allow security modules like | ||
91 | SELinux and Smack to label files to facilitate enforcement of their policies. | ||
92 | Without this an NFSv4 mount will have the same label on each file. | ||
93 | |||
94 | If you do not wish to enable fine-grained security labels SELinux or | ||
95 | Smack policies on NFSv4 files, say N. | ||
96 | |||
97 | WARNING: there is still a chance of backwards-incompatible protocol changes. | ||
98 | For now we recommend "Y" only for developers and testers." | ||
99 | |||
84 | config NFSD_FAULT_INJECTION | 100 | config NFSD_FAULT_INJECTION |
85 | bool "NFS server manual fault injection" | 101 | bool "NFS server manual fault injection" |
86 | depends on NFSD_V4 && DEBUG_KERNEL | 102 | depends on NFSD_V4 && DEBUG_KERNEL |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 27d74a294515..419572f33b72 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -42,6 +42,36 @@ | |||
42 | #include "current_stateid.h" | 42 | #include "current_stateid.h" |
43 | #include "netns.h" | 43 | #include "netns.h" |
44 | 44 | ||
45 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
46 | #include <linux/security.h> | ||
47 | |||
48 | static inline void | ||
49 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | ||
50 | { | ||
51 | struct inode *inode = resfh->fh_dentry->d_inode; | ||
52 | int status; | ||
53 | |||
54 | mutex_lock(&inode->i_mutex); | ||
55 | status = security_inode_setsecctx(resfh->fh_dentry, | ||
56 | label->data, label->len); | ||
57 | mutex_unlock(&inode->i_mutex); | ||
58 | |||
59 | if (status) | ||
60 | /* | ||
61 | * XXX: We should really fail the whole open, but we may | ||
62 | * already have created a new file, so it may be too | ||
63 | * late. For now this seems the least of evils: | ||
64 | */ | ||
65 | bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
66 | |||
67 | return; | ||
68 | } | ||
69 | #else | ||
70 | static inline void | ||
71 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | ||
72 | { } | ||
73 | #endif | ||
74 | |||
45 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 75 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
46 | 76 | ||
47 | static u32 nfsd_attrmask[] = { | 77 | static u32 nfsd_attrmask[] = { |
@@ -239,6 +269,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru | |||
239 | (u32 *)open->op_verf.data, | 269 | (u32 *)open->op_verf.data, |
240 | &open->op_truncate, &open->op_created); | 270 | &open->op_truncate, &open->op_created); |
241 | 271 | ||
272 | if (!status && open->op_label.len) | ||
273 | nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval); | ||
274 | |||
242 | /* | 275 | /* |
243 | * Following rfc 3530 14.2.16, use the returned bitmask | 276 | * Following rfc 3530 14.2.16, use the returned bitmask |
244 | * to indicate which attributes we used to store the | 277 | * to indicate which attributes we used to store the |
@@ -263,7 +296,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru | |||
263 | 296 | ||
264 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); | 297 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); |
265 | accmode = NFSD_MAY_NOP; | 298 | accmode = NFSD_MAY_NOP; |
266 | if (open->op_created) | 299 | if (open->op_created || |
300 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
267 | accmode |= NFSD_MAY_OWNER_OVERRIDE; | 301 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
268 | status = do_open_permission(rqstp, resfh, open, accmode); | 302 | status = do_open_permission(rqstp, resfh, open, accmode); |
269 | set_change_info(&open->op_cinfo, current_fh); | 303 | set_change_info(&open->op_cinfo, current_fh); |
@@ -637,6 +671,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
637 | if (status) | 671 | if (status) |
638 | goto out; | 672 | goto out; |
639 | 673 | ||
674 | if (create->cr_label.len) | ||
675 | nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); | ||
676 | |||
640 | if (create->cr_acl != NULL) | 677 | if (create->cr_acl != NULL) |
641 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, | 678 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, |
642 | create->cr_bmval); | 679 | create->cr_bmval); |
@@ -916,6 +953,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
916 | setattr->sa_acl); | 953 | setattr->sa_acl); |
917 | if (status) | 954 | if (status) |
918 | goto out; | 955 | goto out; |
956 | if (setattr->sa_label.len) | ||
957 | status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, | ||
958 | &setattr->sa_label); | ||
959 | if (status) | ||
960 | goto out; | ||
919 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, | 961 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
920 | 0, (time_t)0); | 962 | 0, (time_t)0); |
921 | out: | 963 | out: |
@@ -1251,7 +1293,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1251 | * According to RFC3010, this takes precedence over all other errors. | 1293 | * According to RFC3010, this takes precedence over all other errors. |
1252 | */ | 1294 | */ |
1253 | status = nfserr_minor_vers_mismatch; | 1295 | status = nfserr_minor_vers_mismatch; |
1254 | if (args->minorversion > nfsd_supported_minorversion) | 1296 | if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0) |
1255 | goto out; | 1297 | goto out; |
1256 | 1298 | ||
1257 | status = nfs41_check_op_ordering(args); | 1299 | status = nfs41_check_op_ordering(args); |
@@ -1482,7 +1524,7 @@ static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | |||
1482 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1524 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1483 | { | 1525 | { |
1484 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ | 1526 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ |
1485 | 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ | 1527 | 1 + 1 + 2 + /* eir_flags, spr_how, spo_must_enforce & _allow */\ |
1486 | 2 + /*eir_server_owner.so_minor_id */\ | 1528 | 2 + /*eir_server_owner.so_minor_id */\ |
1487 | /* eir_server_owner.so_major_id<> */\ | 1529 | /* eir_server_owner.so_major_id<> */\ |
1488 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | 1530 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 4e9a21db867a..105a3b080d12 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -240,11 +240,16 @@ struct name_list { | |||
240 | struct list_head list; | 240 | struct list_head list; |
241 | }; | 241 | }; |
242 | 242 | ||
243 | struct nfs4_dir_ctx { | ||
244 | struct dir_context ctx; | ||
245 | struct list_head names; | ||
246 | }; | ||
247 | |||
243 | static int | 248 | static int |
244 | nfsd4_build_namelist(void *arg, const char *name, int namlen, | 249 | nfsd4_build_namelist(void *arg, const char *name, int namlen, |
245 | loff_t offset, u64 ino, unsigned int d_type) | 250 | loff_t offset, u64 ino, unsigned int d_type) |
246 | { | 251 | { |
247 | struct list_head *names = arg; | 252 | struct nfs4_dir_ctx *ctx = arg; |
248 | struct name_list *entry; | 253 | struct name_list *entry; |
249 | 254 | ||
250 | if (namlen != HEXDIR_LEN - 1) | 255 | if (namlen != HEXDIR_LEN - 1) |
@@ -254,7 +259,7 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, | |||
254 | return -ENOMEM; | 259 | return -ENOMEM; |
255 | memcpy(entry->name, name, HEXDIR_LEN - 1); | 260 | memcpy(entry->name, name, HEXDIR_LEN - 1); |
256 | entry->name[HEXDIR_LEN - 1] = '\0'; | 261 | entry->name[HEXDIR_LEN - 1] = '\0'; |
257 | list_add(&entry->list, names); | 262 | list_add(&entry->list, &ctx->names); |
258 | return 0; | 263 | return 0; |
259 | } | 264 | } |
260 | 265 | ||
@@ -263,7 +268,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) | |||
263 | { | 268 | { |
264 | const struct cred *original_cred; | 269 | const struct cred *original_cred; |
265 | struct dentry *dir = nn->rec_file->f_path.dentry; | 270 | struct dentry *dir = nn->rec_file->f_path.dentry; |
266 | LIST_HEAD(names); | 271 | struct nfs4_dir_ctx ctx = { |
272 | .ctx.actor = nfsd4_build_namelist, | ||
273 | .names = LIST_HEAD_INIT(ctx.names) | ||
274 | }; | ||
267 | int status; | 275 | int status; |
268 | 276 | ||
269 | status = nfs4_save_creds(&original_cred); | 277 | status = nfs4_save_creds(&original_cred); |
@@ -276,11 +284,11 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) | |||
276 | return status; | 284 | return status; |
277 | } | 285 | } |
278 | 286 | ||
279 | status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names); | 287 | status = iterate_dir(nn->rec_file, &ctx.ctx); |
280 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | 288 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
281 | while (!list_empty(&names)) { | 289 | while (!list_empty(&ctx.names)) { |
282 | struct name_list *entry; | 290 | struct name_list *entry; |
283 | entry = list_entry(names.next, struct name_list, list); | 291 | entry = list_entry(ctx.names.next, struct name_list, list); |
284 | if (!status) { | 292 | if (!status) { |
285 | struct dentry *dentry; | 293 | struct dentry *dentry; |
286 | dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); | 294 | dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 316ec843dec2..43f42290e5df 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -97,19 +97,20 @@ nfs4_lock_state(void) | |||
97 | 97 | ||
98 | static void free_session(struct nfsd4_session *); | 98 | static void free_session(struct nfsd4_session *); |
99 | 99 | ||
100 | void nfsd4_put_session(struct nfsd4_session *ses) | 100 | static bool is_session_dead(struct nfsd4_session *ses) |
101 | { | 101 | { |
102 | atomic_dec(&ses->se_ref); | 102 | return ses->se_flags & NFS4_SESSION_DEAD; |
103 | } | 103 | } |
104 | 104 | ||
105 | static bool is_session_dead(struct nfsd4_session *ses) | 105 | void nfsd4_put_session(struct nfsd4_session *ses) |
106 | { | 106 | { |
107 | return ses->se_flags & NFS4_SESSION_DEAD; | 107 | if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) |
108 | free_session(ses); | ||
108 | } | 109 | } |
109 | 110 | ||
110 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses) | 111 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) |
111 | { | 112 | { |
112 | if (atomic_read(&ses->se_ref)) | 113 | if (atomic_read(&ses->se_ref) > ref_held_by_me) |
113 | return nfserr_jukebox; | 114 | return nfserr_jukebox; |
114 | ses->se_flags |= NFS4_SESSION_DEAD; | 115 | ses->se_flags |= NFS4_SESSION_DEAD; |
115 | return nfs_ok; | 116 | return nfs_ok; |
@@ -364,19 +365,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) | |||
364 | } | 365 | } |
365 | 366 | ||
366 | static struct nfs4_delegation * | 367 | static struct nfs4_delegation * |
367 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type) | 368 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) |
368 | { | 369 | { |
369 | struct nfs4_delegation *dp; | 370 | struct nfs4_delegation *dp; |
370 | struct nfs4_file *fp = stp->st_file; | 371 | struct nfs4_file *fp = stp->st_file; |
371 | 372 | ||
372 | dprintk("NFSD alloc_init_deleg\n"); | 373 | dprintk("NFSD alloc_init_deleg\n"); |
373 | /* | ||
374 | * Major work on the lease subsystem (for example, to support | ||
375 | * calbacks on stat) will be required before we can support | ||
376 | * write delegations properly. | ||
377 | */ | ||
378 | if (type != NFS4_OPEN_DELEGATE_READ) | ||
379 | return NULL; | ||
380 | if (fp->fi_had_conflict) | 374 | if (fp->fi_had_conflict) |
381 | return NULL; | 375 | return NULL; |
382 | if (num_delegations > max_delegations) | 376 | if (num_delegations > max_delegations) |
@@ -397,7 +391,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
397 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 391 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
398 | get_nfs4_file(fp); | 392 | get_nfs4_file(fp); |
399 | dp->dl_file = fp; | 393 | dp->dl_file = fp; |
400 | dp->dl_type = type; | 394 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; |
401 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 395 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
402 | dp->dl_time = 0; | 396 | dp->dl_time = 0; |
403 | atomic_set(&dp->dl_count, 1); | 397 | atomic_set(&dp->dl_count, 1); |
@@ -1188,6 +1182,9 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) | |||
1188 | target->cr_gid = source->cr_gid; | 1182 | target->cr_gid = source->cr_gid; |
1189 | target->cr_group_info = source->cr_group_info; | 1183 | target->cr_group_info = source->cr_group_info; |
1190 | get_group_info(target->cr_group_info); | 1184 | get_group_info(target->cr_group_info); |
1185 | target->cr_gss_mech = source->cr_gss_mech; | ||
1186 | if (source->cr_gss_mech) | ||
1187 | gss_mech_get(source->cr_gss_mech); | ||
1191 | return 0; | 1188 | return 0; |
1192 | } | 1189 | } |
1193 | 1190 | ||
@@ -1262,6 +1259,33 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
1262 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | 1259 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); |
1263 | } | 1260 | } |
1264 | 1261 | ||
1262 | static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) | ||
1263 | { | ||
1264 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1265 | u32 service; | ||
1266 | |||
1267 | if (!cr->cr_gss_mech) | ||
1268 | return false; | ||
1269 | service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); | ||
1270 | return service == RPC_GSS_SVC_INTEGRITY || | ||
1271 | service == RPC_GSS_SVC_PRIVACY; | ||
1272 | } | ||
1273 | |||
1274 | static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) | ||
1275 | { | ||
1276 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1277 | |||
1278 | if (!cl->cl_mach_cred) | ||
1279 | return true; | ||
1280 | if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) | ||
1281 | return false; | ||
1282 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1283 | return false; | ||
1284 | if (!cr->cr_principal) | ||
1285 | return false; | ||
1286 | return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); | ||
1287 | } | ||
1288 | |||
1265 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) | 1289 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) |
1266 | { | 1290 | { |
1267 | static u32 current_clientid = 1; | 1291 | static u32 current_clientid = 1; |
@@ -1639,16 +1663,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1639 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) | 1663 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) |
1640 | return nfserr_inval; | 1664 | return nfserr_inval; |
1641 | 1665 | ||
1642 | /* Currently only support SP4_NONE */ | ||
1643 | switch (exid->spa_how) { | 1666 | switch (exid->spa_how) { |
1667 | case SP4_MACH_CRED: | ||
1668 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1669 | return nfserr_inval; | ||
1644 | case SP4_NONE: | 1670 | case SP4_NONE: |
1645 | break; | 1671 | break; |
1646 | default: /* checked by xdr code */ | 1672 | default: /* checked by xdr code */ |
1647 | WARN_ON_ONCE(1); | 1673 | WARN_ON_ONCE(1); |
1648 | case SP4_SSV: | 1674 | case SP4_SSV: |
1649 | return nfserr_encr_alg_unsupp; | 1675 | return nfserr_encr_alg_unsupp; |
1650 | case SP4_MACH_CRED: | ||
1651 | return nfserr_serverfault; /* no excuse :-/ */ | ||
1652 | } | 1676 | } |
1653 | 1677 | ||
1654 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1678 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
@@ -1663,6 +1687,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1663 | status = nfserr_inval; | 1687 | status = nfserr_inval; |
1664 | goto out; | 1688 | goto out; |
1665 | } | 1689 | } |
1690 | if (!mach_creds_match(conf, rqstp)) { | ||
1691 | status = nfserr_wrong_cred; | ||
1692 | goto out; | ||
1693 | } | ||
1666 | if (!creds_match) { /* case 9 */ | 1694 | if (!creds_match) { /* case 9 */ |
1667 | status = nfserr_perm; | 1695 | status = nfserr_perm; |
1668 | goto out; | 1696 | goto out; |
@@ -1709,7 +1737,8 @@ out_new: | |||
1709 | status = nfserr_jukebox; | 1737 | status = nfserr_jukebox; |
1710 | goto out; | 1738 | goto out; |
1711 | } | 1739 | } |
1712 | new->cl_minorversion = 1; | 1740 | new->cl_minorversion = cstate->minorversion; |
1741 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); | ||
1713 | 1742 | ||
1714 | gen_clid(new, nn); | 1743 | gen_clid(new, nn); |
1715 | add_to_unconfirmed(new); | 1744 | add_to_unconfirmed(new); |
@@ -1839,6 +1868,24 @@ static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) | |||
1839 | return nfs_ok; | 1868 | return nfs_ok; |
1840 | } | 1869 | } |
1841 | 1870 | ||
1871 | static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) | ||
1872 | { | ||
1873 | switch (cbs->flavor) { | ||
1874 | case RPC_AUTH_NULL: | ||
1875 | case RPC_AUTH_UNIX: | ||
1876 | return nfs_ok; | ||
1877 | default: | ||
1878 | /* | ||
1879 | * GSS case: the spec doesn't allow us to return this | ||
1880 | * error. But it also doesn't allow us not to support | ||
1881 | * GSS. | ||
1882 | * I'd rather this fail hard than return some error the | ||
1883 | * client might think it can already handle: | ||
1884 | */ | ||
1885 | return nfserr_encr_alg_unsupp; | ||
1886 | } | ||
1887 | } | ||
1888 | |||
1842 | __be32 | 1889 | __be32 |
1843 | nfsd4_create_session(struct svc_rqst *rqstp, | 1890 | nfsd4_create_session(struct svc_rqst *rqstp, |
1844 | struct nfsd4_compound_state *cstate, | 1891 | struct nfsd4_compound_state *cstate, |
@@ -1854,6 +1901,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1854 | 1901 | ||
1855 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1902 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1856 | return nfserr_inval; | 1903 | return nfserr_inval; |
1904 | status = nfsd4_check_cb_sec(&cr_ses->cb_sec); | ||
1905 | if (status) | ||
1906 | return status; | ||
1857 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); | 1907 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); |
1858 | if (status) | 1908 | if (status) |
1859 | return status; | 1909 | return status; |
@@ -1874,6 +1924,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1874 | WARN_ON_ONCE(conf && unconf); | 1924 | WARN_ON_ONCE(conf && unconf); |
1875 | 1925 | ||
1876 | if (conf) { | 1926 | if (conf) { |
1927 | status = nfserr_wrong_cred; | ||
1928 | if (!mach_creds_match(conf, rqstp)) | ||
1929 | goto out_free_conn; | ||
1877 | cs_slot = &conf->cl_cs_slot; | 1930 | cs_slot = &conf->cl_cs_slot; |
1878 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1931 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1879 | if (status == nfserr_replay_cache) { | 1932 | if (status == nfserr_replay_cache) { |
@@ -1890,6 +1943,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1890 | status = nfserr_clid_inuse; | 1943 | status = nfserr_clid_inuse; |
1891 | goto out_free_conn; | 1944 | goto out_free_conn; |
1892 | } | 1945 | } |
1946 | status = nfserr_wrong_cred; | ||
1947 | if (!mach_creds_match(unconf, rqstp)) | ||
1948 | goto out_free_conn; | ||
1893 | cs_slot = &unconf->cl_cs_slot; | 1949 | cs_slot = &unconf->cl_cs_slot; |
1894 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1950 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1895 | if (status) { | 1951 | if (status) { |
@@ -1957,7 +2013,11 @@ __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state | |||
1957 | { | 2013 | { |
1958 | struct nfsd4_session *session = cstate->session; | 2014 | struct nfsd4_session *session = cstate->session; |
1959 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 2015 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2016 | __be32 status; | ||
1960 | 2017 | ||
2018 | status = nfsd4_check_cb_sec(&bc->bc_cb_sec); | ||
2019 | if (status) | ||
2020 | return status; | ||
1961 | spin_lock(&nn->client_lock); | 2021 | spin_lock(&nn->client_lock); |
1962 | session->se_cb_prog = bc->bc_cb_program; | 2022 | session->se_cb_prog = bc->bc_cb_program; |
1963 | session->se_cb_sec = bc->bc_cb_sec; | 2023 | session->se_cb_sec = bc->bc_cb_sec; |
@@ -1986,6 +2046,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | |||
1986 | status = nfserr_badsession; | 2046 | status = nfserr_badsession; |
1987 | if (!session) | 2047 | if (!session) |
1988 | goto out; | 2048 | goto out; |
2049 | status = nfserr_wrong_cred; | ||
2050 | if (!mach_creds_match(session->se_client, rqstp)) | ||
2051 | goto out; | ||
1989 | status = nfsd4_map_bcts_dir(&bcts->dir); | 2052 | status = nfsd4_map_bcts_dir(&bcts->dir); |
1990 | if (status) | 2053 | if (status) |
1991 | goto out; | 2054 | goto out; |
@@ -2014,6 +2077,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2014 | { | 2077 | { |
2015 | struct nfsd4_session *ses; | 2078 | struct nfsd4_session *ses; |
2016 | __be32 status; | 2079 | __be32 status; |
2080 | int ref_held_by_me = 0; | ||
2017 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); | 2081 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); |
2018 | 2082 | ||
2019 | nfs4_lock_state(); | 2083 | nfs4_lock_state(); |
@@ -2021,6 +2085,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2021 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { | 2085 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { |
2022 | if (!nfsd4_last_compound_op(r)) | 2086 | if (!nfsd4_last_compound_op(r)) |
2023 | goto out; | 2087 | goto out; |
2088 | ref_held_by_me++; | ||
2024 | } | 2089 | } |
2025 | dump_sessionid(__func__, &sessionid->sessionid); | 2090 | dump_sessionid(__func__, &sessionid->sessionid); |
2026 | spin_lock(&nn->client_lock); | 2091 | spin_lock(&nn->client_lock); |
@@ -2028,17 +2093,22 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2028 | status = nfserr_badsession; | 2093 | status = nfserr_badsession; |
2029 | if (!ses) | 2094 | if (!ses) |
2030 | goto out_client_lock; | 2095 | goto out_client_lock; |
2031 | status = mark_session_dead_locked(ses); | 2096 | status = nfserr_wrong_cred; |
2032 | if (status) | 2097 | if (!mach_creds_match(ses->se_client, r)) |
2033 | goto out_client_lock; | 2098 | goto out_client_lock; |
2099 | nfsd4_get_session_locked(ses); | ||
2100 | status = mark_session_dead_locked(ses, 1 + ref_held_by_me); | ||
2101 | if (status) | ||
2102 | goto out_put_session; | ||
2034 | unhash_session(ses); | 2103 | unhash_session(ses); |
2035 | spin_unlock(&nn->client_lock); | 2104 | spin_unlock(&nn->client_lock); |
2036 | 2105 | ||
2037 | nfsd4_probe_callback_sync(ses->se_client); | 2106 | nfsd4_probe_callback_sync(ses->se_client); |
2038 | 2107 | ||
2039 | spin_lock(&nn->client_lock); | 2108 | spin_lock(&nn->client_lock); |
2040 | free_session(ses); | ||
2041 | status = nfs_ok; | 2109 | status = nfs_ok; |
2110 | out_put_session: | ||
2111 | nfsd4_put_session(ses); | ||
2042 | out_client_lock: | 2112 | out_client_lock: |
2043 | spin_unlock(&nn->client_lock); | 2113 | spin_unlock(&nn->client_lock); |
2044 | out: | 2114 | out: |
@@ -2058,26 +2128,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s | |||
2058 | return NULL; | 2128 | return NULL; |
2059 | } | 2129 | } |
2060 | 2130 | ||
2061 | static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) | 2131 | static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) |
2062 | { | 2132 | { |
2063 | struct nfs4_client *clp = ses->se_client; | 2133 | struct nfs4_client *clp = ses->se_client; |
2064 | struct nfsd4_conn *c; | 2134 | struct nfsd4_conn *c; |
2135 | __be32 status = nfs_ok; | ||
2065 | int ret; | 2136 | int ret; |
2066 | 2137 | ||
2067 | spin_lock(&clp->cl_lock); | 2138 | spin_lock(&clp->cl_lock); |
2068 | c = __nfsd4_find_conn(new->cn_xprt, ses); | 2139 | c = __nfsd4_find_conn(new->cn_xprt, ses); |
2069 | if (c) { | 2140 | if (c) |
2070 | spin_unlock(&clp->cl_lock); | 2141 | goto out_free; |
2071 | free_conn(new); | 2142 | status = nfserr_conn_not_bound_to_session; |
2072 | return; | 2143 | if (clp->cl_mach_cred) |
2073 | } | 2144 | goto out_free; |
2074 | __nfsd4_hash_conn(new, ses); | 2145 | __nfsd4_hash_conn(new, ses); |
2075 | spin_unlock(&clp->cl_lock); | 2146 | spin_unlock(&clp->cl_lock); |
2076 | ret = nfsd4_register_conn(new); | 2147 | ret = nfsd4_register_conn(new); |
2077 | if (ret) | 2148 | if (ret) |
2078 | /* oops; xprt is already down: */ | 2149 | /* oops; xprt is already down: */ |
2079 | nfsd4_conn_lost(&new->cn_xpt_user); | 2150 | nfsd4_conn_lost(&new->cn_xpt_user); |
2080 | return; | 2151 | return nfs_ok; |
2152 | out_free: | ||
2153 | spin_unlock(&clp->cl_lock); | ||
2154 | free_conn(new); | ||
2155 | return status; | ||
2081 | } | 2156 | } |
2082 | 2157 | ||
2083 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) | 2158 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) |
@@ -2169,8 +2244,10 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2169 | if (status) | 2244 | if (status) |
2170 | goto out_put_session; | 2245 | goto out_put_session; |
2171 | 2246 | ||
2172 | nfsd4_sequence_check_conn(conn, session); | 2247 | status = nfsd4_sequence_check_conn(conn, session); |
2173 | conn = NULL; | 2248 | conn = NULL; |
2249 | if (status) | ||
2250 | goto out_put_session; | ||
2174 | 2251 | ||
2175 | /* Success! bump slot seqid */ | 2252 | /* Success! bump slot seqid */ |
2176 | slot->sl_seqid = seq->seqid; | 2253 | slot->sl_seqid = seq->seqid; |
@@ -2232,7 +2309,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2232 | status = nfserr_stale_clientid; | 2309 | status = nfserr_stale_clientid; |
2233 | goto out; | 2310 | goto out; |
2234 | } | 2311 | } |
2235 | 2312 | if (!mach_creds_match(clp, rqstp)) { | |
2313 | status = nfserr_wrong_cred; | ||
2314 | goto out; | ||
2315 | } | ||
2236 | expire_client(clp); | 2316 | expire_client(clp); |
2237 | out: | 2317 | out: |
2238 | nfs4_unlock_state(); | 2318 | nfs4_unlock_state(); |
@@ -2645,13 +2725,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) | |||
2645 | 2725 | ||
2646 | list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); | 2726 | list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); |
2647 | 2727 | ||
2648 | /* only place dl_time is set. protected by lock_flocks*/ | 2728 | /* Only place dl_time is set; protected by i_lock: */ |
2649 | dp->dl_time = get_seconds(); | 2729 | dp->dl_time = get_seconds(); |
2650 | 2730 | ||
2651 | nfsd4_cb_recall(dp); | 2731 | nfsd4_cb_recall(dp); |
2652 | } | 2732 | } |
2653 | 2733 | ||
2654 | /* Called from break_lease() with lock_flocks() held. */ | 2734 | /* Called from break_lease() with i_lock held. */ |
2655 | static void nfsd_break_deleg_cb(struct file_lock *fl) | 2735 | static void nfsd_break_deleg_cb(struct file_lock *fl) |
2656 | { | 2736 | { |
2657 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; | 2737 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; |
@@ -2940,13 +3020,13 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f | |||
2940 | return fl; | 3020 | return fl; |
2941 | } | 3021 | } |
2942 | 3022 | ||
2943 | static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | 3023 | static int nfs4_setlease(struct nfs4_delegation *dp) |
2944 | { | 3024 | { |
2945 | struct nfs4_file *fp = dp->dl_file; | 3025 | struct nfs4_file *fp = dp->dl_file; |
2946 | struct file_lock *fl; | 3026 | struct file_lock *fl; |
2947 | int status; | 3027 | int status; |
2948 | 3028 | ||
2949 | fl = nfs4_alloc_init_lease(dp, flag); | 3029 | fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); |
2950 | if (!fl) | 3030 | if (!fl) |
2951 | return -ENOMEM; | 3031 | return -ENOMEM; |
2952 | fl->fl_file = find_readable_file(fp); | 3032 | fl->fl_file = find_readable_file(fp); |
@@ -2964,12 +3044,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | |||
2964 | return 0; | 3044 | return 0; |
2965 | } | 3045 | } |
2966 | 3046 | ||
2967 | static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | 3047 | static int nfs4_set_delegation(struct nfs4_delegation *dp) |
2968 | { | 3048 | { |
2969 | struct nfs4_file *fp = dp->dl_file; | 3049 | struct nfs4_file *fp = dp->dl_file; |
2970 | 3050 | ||
2971 | if (!fp->fi_lease) | 3051 | if (!fp->fi_lease) |
2972 | return nfs4_setlease(dp, flag); | 3052 | return nfs4_setlease(dp); |
2973 | spin_lock(&recall_lock); | 3053 | spin_lock(&recall_lock); |
2974 | if (fp->fi_had_conflict) { | 3054 | if (fp->fi_had_conflict) { |
2975 | spin_unlock(&recall_lock); | 3055 | spin_unlock(&recall_lock); |
@@ -3005,6 +3085,9 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | |||
3005 | 3085 | ||
3006 | /* | 3086 | /* |
3007 | * Attempt to hand out a delegation. | 3087 | * Attempt to hand out a delegation. |
3088 | * | ||
3089 | * Note we don't support write delegations, and won't until the vfs has | ||
3090 | * proper support for them. | ||
3008 | */ | 3091 | */ |
3009 | static void | 3092 | static void |
3010 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, | 3093 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, |
@@ -3013,39 +3096,45 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3013 | struct nfs4_delegation *dp; | 3096 | struct nfs4_delegation *dp; |
3014 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); | 3097 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); |
3015 | int cb_up; | 3098 | int cb_up; |
3016 | int status = 0, flag = 0; | 3099 | int status = 0; |
3017 | 3100 | ||
3018 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); | 3101 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); |
3019 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
3020 | open->op_recall = 0; | 3102 | open->op_recall = 0; |
3021 | switch (open->op_claim_type) { | 3103 | switch (open->op_claim_type) { |
3022 | case NFS4_OPEN_CLAIM_PREVIOUS: | 3104 | case NFS4_OPEN_CLAIM_PREVIOUS: |
3023 | if (!cb_up) | 3105 | if (!cb_up) |
3024 | open->op_recall = 1; | 3106 | open->op_recall = 1; |
3025 | flag = open->op_delegate_type; | 3107 | if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) |
3026 | if (flag == NFS4_OPEN_DELEGATE_NONE) | 3108 | goto out_no_deleg; |
3027 | goto out; | ||
3028 | break; | 3109 | break; |
3029 | case NFS4_OPEN_CLAIM_NULL: | 3110 | case NFS4_OPEN_CLAIM_NULL: |
3030 | /* Let's not give out any delegations till everyone's | 3111 | /* |
3031 | * had the chance to reclaim theirs.... */ | 3112 | * Let's not give out any delegations till everyone's |
3113 | * had the chance to reclaim theirs.... | ||
3114 | */ | ||
3032 | if (locks_in_grace(net)) | 3115 | if (locks_in_grace(net)) |
3033 | goto out; | 3116 | goto out_no_deleg; |
3034 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) | 3117 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) |
3035 | goto out; | 3118 | goto out_no_deleg; |
3119 | /* | ||
3120 | * Also, if the file was opened for write or | ||
3121 | * create, there's a good chance the client's | ||
3122 | * about to write to it, resulting in an | ||
3123 | * immediate recall (since we don't support | ||
3124 | * write delegations): | ||
3125 | */ | ||
3036 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 3126 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
3037 | flag = NFS4_OPEN_DELEGATE_WRITE; | 3127 | goto out_no_deleg; |
3038 | else | 3128 | if (open->op_create == NFS4_OPEN_CREATE) |
3039 | flag = NFS4_OPEN_DELEGATE_READ; | 3129 | goto out_no_deleg; |
3040 | break; | 3130 | break; |
3041 | default: | 3131 | default: |
3042 | goto out; | 3132 | goto out_no_deleg; |
3043 | } | 3133 | } |
3044 | 3134 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); | |
3045 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); | ||
3046 | if (dp == NULL) | 3135 | if (dp == NULL) |
3047 | goto out_no_deleg; | 3136 | goto out_no_deleg; |
3048 | status = nfs4_set_delegation(dp, flag); | 3137 | status = nfs4_set_delegation(dp); |
3049 | if (status) | 3138 | if (status) |
3050 | goto out_free; | 3139 | goto out_free; |
3051 | 3140 | ||
@@ -3053,24 +3142,23 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3053 | 3142 | ||
3054 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", | 3143 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", |
3055 | STATEID_VAL(&dp->dl_stid.sc_stateid)); | 3144 | STATEID_VAL(&dp->dl_stid.sc_stateid)); |
3056 | out: | 3145 | open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; |
3057 | open->op_delegate_type = flag; | ||
3058 | if (flag == NFS4_OPEN_DELEGATE_NONE) { | ||
3059 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && | ||
3060 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
3061 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
3062 | |||
3063 | /* 4.1 client asking for a delegation? */ | ||
3064 | if (open->op_deleg_want) | ||
3065 | nfsd4_open_deleg_none_ext(open, status); | ||
3066 | } | ||
3067 | return; | 3146 | return; |
3068 | out_free: | 3147 | out_free: |
3069 | unhash_stid(&dp->dl_stid); | 3148 | unhash_stid(&dp->dl_stid); |
3070 | nfs4_put_delegation(dp); | 3149 | nfs4_put_delegation(dp); |
3071 | out_no_deleg: | 3150 | out_no_deleg: |
3072 | flag = NFS4_OPEN_DELEGATE_NONE; | 3151 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; |
3073 | goto out; | 3152 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && |
3153 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { | ||
3154 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
3155 | open->op_recall = 1; | ||
3156 | } | ||
3157 | |||
3158 | /* 4.1 client asking for a delegation? */ | ||
3159 | if (open->op_deleg_want) | ||
3160 | nfsd4_open_deleg_none_ext(open, status); | ||
3161 | return; | ||
3074 | } | 3162 | } |
3075 | 3163 | ||
3076 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, | 3164 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, |
@@ -3427,7 +3515,7 @@ grace_disallows_io(struct net *net, struct inode *inode) | |||
3427 | /* Returns true iff a is later than b: */ | 3515 | /* Returns true iff a is later than b: */ |
3428 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) | 3516 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) |
3429 | { | 3517 | { |
3430 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3518 | return (s32)(a->si_generation - b->si_generation) > 0; |
3431 | } | 3519 | } |
3432 | 3520 | ||
3433 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3521 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
@@ -4435,7 +4523,6 @@ __be32 | |||
4435 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 4523 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
4436 | struct nfsd4_locku *locku) | 4524 | struct nfsd4_locku *locku) |
4437 | { | 4525 | { |
4438 | struct nfs4_lockowner *lo; | ||
4439 | struct nfs4_ol_stateid *stp; | 4526 | struct nfs4_ol_stateid *stp; |
4440 | struct file *filp = NULL; | 4527 | struct file *filp = NULL; |
4441 | struct file_lock *file_lock = NULL; | 4528 | struct file_lock *file_lock = NULL; |
@@ -4468,10 +4555,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4468 | status = nfserr_jukebox; | 4555 | status = nfserr_jukebox; |
4469 | goto out; | 4556 | goto out; |
4470 | } | 4557 | } |
4471 | lo = lockowner(stp->st_stateowner); | ||
4472 | locks_init_lock(file_lock); | 4558 | locks_init_lock(file_lock); |
4473 | file_lock->fl_type = F_UNLCK; | 4559 | file_lock->fl_type = F_UNLCK; |
4474 | file_lock->fl_owner = (fl_owner_t)lo; | 4560 | file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); |
4475 | file_lock->fl_pid = current->tgid; | 4561 | file_lock->fl_pid = current->tgid; |
4476 | file_lock->fl_file = filp; | 4562 | file_lock->fl_file = filp; |
4477 | file_lock->fl_flags = FL_POSIX; | 4563 | file_lock->fl_flags = FL_POSIX; |
@@ -4490,11 +4576,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4490 | update_stateid(&stp->st_stid.sc_stateid); | 4576 | update_stateid(&stp->st_stid.sc_stateid); |
4491 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4577 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
4492 | 4578 | ||
4493 | if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) { | ||
4494 | WARN_ON_ONCE(cstate->replay_owner); | ||
4495 | release_lockowner(lo); | ||
4496 | } | ||
4497 | |||
4498 | out: | 4579 | out: |
4499 | nfsd4_bump_seqid(cstate, status); | 4580 | nfsd4_bump_seqid(cstate, status); |
4500 | if (!cstate->replay_owner) | 4581 | if (!cstate->replay_owner) |
@@ -4520,7 +4601,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) | |||
4520 | struct inode *inode = filp->fi_inode; | 4601 | struct inode *inode = filp->fi_inode; |
4521 | int status = 0; | 4602 | int status = 0; |
4522 | 4603 | ||
4523 | lock_flocks(); | 4604 | spin_lock(&inode->i_lock); |
4524 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { | 4605 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { |
4525 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { | 4606 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { |
4526 | status = 1; | 4607 | status = 1; |
@@ -4528,7 +4609,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) | |||
4528 | } | 4609 | } |
4529 | } | 4610 | } |
4530 | out: | 4611 | out: |
4531 | unlock_flocks(); | 4612 | spin_unlock(&inode->i_lock); |
4532 | return status; | 4613 | return status; |
4533 | } | 4614 | } |
4534 | 4615 | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6cd86e0fe450..c2a4701d7286 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -55,6 +55,11 @@ | |||
55 | #include "cache.h" | 55 | #include "cache.h" |
56 | #include "netns.h" | 56 | #include "netns.h" |
57 | 57 | ||
58 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
59 | #include <linux/security.h> | ||
60 | #endif | ||
61 | |||
62 | |||
58 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 63 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
59 | 64 | ||
60 | /* | 65 | /* |
@@ -134,6 +139,19 @@ xdr_error: \ | |||
134 | } \ | 139 | } \ |
135 | } while (0) | 140 | } while (0) |
136 | 141 | ||
142 | static void next_decode_page(struct nfsd4_compoundargs *argp) | ||
143 | { | ||
144 | argp->pagelist++; | ||
145 | argp->p = page_address(argp->pagelist[0]); | ||
146 | if (argp->pagelen < PAGE_SIZE) { | ||
147 | argp->end = argp->p + (argp->pagelen>>2); | ||
148 | argp->pagelen = 0; | ||
149 | } else { | ||
150 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
151 | argp->pagelen -= PAGE_SIZE; | ||
152 | } | ||
153 | } | ||
154 | |||
137 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | 155 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) |
138 | { | 156 | { |
139 | /* We want more bytes than seem to be available. | 157 | /* We want more bytes than seem to be available. |
@@ -161,16 +179,7 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | |||
161 | * guarantee p points to at least nbytes bytes. | 179 | * guarantee p points to at least nbytes bytes. |
162 | */ | 180 | */ |
163 | memcpy(p, argp->p, avail); | 181 | memcpy(p, argp->p, avail); |
164 | /* step to next page */ | 182 | next_decode_page(argp); |
165 | argp->p = page_address(argp->pagelist[0]); | ||
166 | argp->pagelist++; | ||
167 | if (argp->pagelen < PAGE_SIZE) { | ||
168 | argp->end = argp->p + (argp->pagelen>>2); | ||
169 | argp->pagelen = 0; | ||
170 | } else { | ||
171 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
172 | argp->pagelen -= PAGE_SIZE; | ||
173 | } | ||
174 | memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); | 183 | memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); |
175 | argp->p += XDR_QUADLEN(nbytes - avail); | 184 | argp->p += XDR_QUADLEN(nbytes - avail); |
176 | return p; | 185 | return p; |
@@ -242,7 +251,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
242 | 251 | ||
243 | static __be32 | 252 | static __be32 |
244 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | 253 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
245 | struct iattr *iattr, struct nfs4_acl **acl) | 254 | struct iattr *iattr, struct nfs4_acl **acl, |
255 | struct xdr_netobj *label) | ||
246 | { | 256 | { |
247 | int expected_len, len = 0; | 257 | int expected_len, len = 0; |
248 | u32 dummy32; | 258 | u32 dummy32; |
@@ -380,6 +390,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
380 | goto xdr_error; | 390 | goto xdr_error; |
381 | } | 391 | } |
382 | } | 392 | } |
393 | |||
394 | label->len = 0; | ||
395 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
396 | if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { | ||
397 | READ_BUF(4); | ||
398 | len += 4; | ||
399 | READ32(dummy32); /* lfs: we don't use it */ | ||
400 | READ_BUF(4); | ||
401 | len += 4; | ||
402 | READ32(dummy32); /* pi: we don't use it either */ | ||
403 | READ_BUF(4); | ||
404 | len += 4; | ||
405 | READ32(dummy32); | ||
406 | READ_BUF(dummy32); | ||
407 | if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN) | ||
408 | return nfserr_badlabel; | ||
409 | len += (XDR_QUADLEN(dummy32) << 2); | ||
410 | READMEM(buf, dummy32); | ||
411 | label->data = kzalloc(dummy32 + 1, GFP_KERNEL); | ||
412 | if (!label->data) | ||
413 | return nfserr_jukebox; | ||
414 | defer_free(argp, kfree, label->data); | ||
415 | memcpy(label->data, buf, dummy32); | ||
416 | } | ||
417 | #endif | ||
418 | |||
383 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 | 419 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
384 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 | 420 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
385 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | 421 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) |
@@ -428,7 +464,11 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ | |||
428 | /* callback_sec_params4 */ | 464 | /* callback_sec_params4 */ |
429 | READ_BUF(4); | 465 | READ_BUF(4); |
430 | READ32(nr_secflavs); | 466 | READ32(nr_secflavs); |
431 | cbs->flavor = (u32)(-1); | 467 | if (nr_secflavs) |
468 | cbs->flavor = (u32)(-1); | ||
469 | else | ||
470 | /* Is this legal? Be generous, take it to mean AUTH_NONE: */ | ||
471 | cbs->flavor = 0; | ||
432 | for (i = 0; i < nr_secflavs; ++i) { | 472 | for (i = 0; i < nr_secflavs; ++i) { |
433 | READ_BUF(4); | 473 | READ_BUF(4); |
434 | READ32(dummy); | 474 | READ32(dummy); |
@@ -576,7 +616,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
576 | return status; | 616 | return status; |
577 | 617 | ||
578 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, | 618 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
579 | &create->cr_acl); | 619 | &create->cr_acl, &create->cr_label); |
580 | if (status) | 620 | if (status) |
581 | goto out; | 621 | goto out; |
582 | 622 | ||
@@ -827,7 +867,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
827 | case NFS4_CREATE_UNCHECKED: | 867 | case NFS4_CREATE_UNCHECKED: |
828 | case NFS4_CREATE_GUARDED: | 868 | case NFS4_CREATE_GUARDED: |
829 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 869 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
830 | &open->op_iattr, &open->op_acl); | 870 | &open->op_iattr, &open->op_acl, &open->op_label); |
831 | if (status) | 871 | if (status) |
832 | goto out; | 872 | goto out; |
833 | break; | 873 | break; |
@@ -841,7 +881,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
841 | READ_BUF(NFS4_VERIFIER_SIZE); | 881 | READ_BUF(NFS4_VERIFIER_SIZE); |
842 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); | 882 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); |
843 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 883 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
844 | &open->op_iattr, &open->op_acl); | 884 | &open->op_iattr, &open->op_acl, &open->op_label); |
845 | if (status) | 885 | if (status) |
846 | goto out; | 886 | goto out; |
847 | break; | 887 | break; |
@@ -1063,7 +1103,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
1063 | if (status) | 1103 | if (status) |
1064 | return status; | 1104 | return status; |
1065 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, | 1105 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
1066 | &setattr->sa_acl); | 1106 | &setattr->sa_acl, &setattr->sa_label); |
1067 | } | 1107 | } |
1068 | 1108 | ||
1069 | static __be32 | 1109 | static __be32 |
@@ -1567,6 +1607,7 @@ struct nfsd4_minorversion_ops { | |||
1567 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { | 1607 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { |
1568 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, | 1608 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, |
1569 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | 1609 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, |
1610 | [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | ||
1570 | }; | 1611 | }; |
1571 | 1612 | ||
1572 | static __be32 | 1613 | static __be32 |
@@ -1953,6 +1994,36 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace, | |||
1953 | FATTR4_WORD0_RDATTR_ERROR) | 1994 | FATTR4_WORD0_RDATTR_ERROR) |
1954 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID | 1995 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID |
1955 | 1996 | ||
1997 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
1998 | static inline __be32 | ||
1999 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
2000 | { | ||
2001 | __be32 *p = *pp; | ||
2002 | |||
2003 | if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) | ||
2004 | return nfserr_resource; | ||
2005 | |||
2006 | /* | ||
2007 | * For now we use a 0 here to indicate the null translation; in | ||
2008 | * the future we may place a call to translation code here. | ||
2009 | */ | ||
2010 | if ((*buflen -= 8) < 0) | ||
2011 | return nfserr_resource; | ||
2012 | |||
2013 | WRITE32(0); /* lfs */ | ||
2014 | WRITE32(0); /* pi */ | ||
2015 | p = xdr_encode_opaque(p, context, len); | ||
2016 | *buflen -= (XDR_QUADLEN(len) << 2) + 4; | ||
2017 | |||
2018 | *pp = p; | ||
2019 | return 0; | ||
2020 | } | ||
2021 | #else | ||
2022 | static inline __be32 | ||
2023 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
2024 | { return 0; } | ||
2025 | #endif | ||
2026 | |||
1956 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | 2027 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) |
1957 | { | 2028 | { |
1958 | /* As per referral draft: */ | 2029 | /* As per referral draft: */ |
@@ -2012,6 +2083,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2012 | int err; | 2083 | int err; |
2013 | int aclsupport = 0; | 2084 | int aclsupport = 0; |
2014 | struct nfs4_acl *acl = NULL; | 2085 | struct nfs4_acl *acl = NULL; |
2086 | void *context = NULL; | ||
2087 | int contextlen; | ||
2088 | bool contextsupport = false; | ||
2015 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2089 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
2016 | u32 minorversion = resp->cstate.minorversion; | 2090 | u32 minorversion = resp->cstate.minorversion; |
2017 | struct path path = { | 2091 | struct path path = { |
@@ -2065,6 +2139,21 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2065 | } | 2139 | } |
2066 | } | 2140 | } |
2067 | 2141 | ||
2142 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2143 | if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || | ||
2144 | bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { | ||
2145 | err = security_inode_getsecctx(dentry->d_inode, | ||
2146 | &context, &contextlen); | ||
2147 | contextsupport = (err == 0); | ||
2148 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2149 | if (err == -EOPNOTSUPP) | ||
2150 | bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2151 | else if (err) | ||
2152 | goto out_nfserr; | ||
2153 | } | ||
2154 | } | ||
2155 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2156 | |||
2068 | if (bmval2) { | 2157 | if (bmval2) { |
2069 | if ((buflen -= 16) < 0) | 2158 | if ((buflen -= 16) < 0) |
2070 | goto out_resource; | 2159 | goto out_resource; |
@@ -2093,6 +2182,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2093 | 2182 | ||
2094 | if (!aclsupport) | 2183 | if (!aclsupport) |
2095 | word0 &= ~FATTR4_WORD0_ACL; | 2184 | word0 &= ~FATTR4_WORD0_ACL; |
2185 | if (!contextsupport) | ||
2186 | word2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2096 | if (!word2) { | 2187 | if (!word2) { |
2097 | if ((buflen -= 12) < 0) | 2188 | if ((buflen -= 12) < 0) |
2098 | goto out_resource; | 2189 | goto out_resource; |
@@ -2400,6 +2491,12 @@ out_acl: | |||
2400 | get_parent_attributes(exp, &stat); | 2491 | get_parent_attributes(exp, &stat); |
2401 | WRITE64(stat.ino); | 2492 | WRITE64(stat.ino); |
2402 | } | 2493 | } |
2494 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2495 | status = nfsd4_encode_security_label(rqstp, context, | ||
2496 | contextlen, &p, &buflen); | ||
2497 | if (status) | ||
2498 | goto out; | ||
2499 | } | ||
2403 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2500 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
2404 | WRITE32(3); | 2501 | WRITE32(3); |
2405 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); | 2502 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); |
@@ -2412,6 +2509,10 @@ out_acl: | |||
2412 | status = nfs_ok; | 2509 | status = nfs_ok; |
2413 | 2510 | ||
2414 | out: | 2511 | out: |
2512 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2513 | if (context) | ||
2514 | security_release_secctx(context, contextlen); | ||
2515 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2415 | kfree(acl); | 2516 | kfree(acl); |
2416 | if (fhp == &tempfh) | 2517 | if (fhp == &tempfh) |
2417 | fh_put(&tempfh); | 2518 | fh_put(&tempfh); |
@@ -3176,16 +3277,18 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3176 | { | 3277 | { |
3177 | __be32 *p; | 3278 | __be32 *p; |
3178 | 3279 | ||
3179 | RESERVE_SPACE(12); | 3280 | RESERVE_SPACE(16); |
3180 | if (nfserr) { | 3281 | if (nfserr) { |
3181 | WRITE32(2); | 3282 | WRITE32(3); |
3283 | WRITE32(0); | ||
3182 | WRITE32(0); | 3284 | WRITE32(0); |
3183 | WRITE32(0); | 3285 | WRITE32(0); |
3184 | } | 3286 | } |
3185 | else { | 3287 | else { |
3186 | WRITE32(2); | 3288 | WRITE32(3); |
3187 | WRITE32(setattr->sa_bmval[0]); | 3289 | WRITE32(setattr->sa_bmval[0]); |
3188 | WRITE32(setattr->sa_bmval[1]); | 3290 | WRITE32(setattr->sa_bmval[1]); |
3291 | WRITE32(setattr->sa_bmval[2]); | ||
3189 | } | 3292 | } |
3190 | ADJUST_ARGS(); | 3293 | ADJUST_ARGS(); |
3191 | return nfserr; | 3294 | return nfserr; |
@@ -3226,6 +3329,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3226 | return nfserr; | 3329 | return nfserr; |
3227 | } | 3330 | } |
3228 | 3331 | ||
3332 | static const u32 nfs4_minimal_spo_must_enforce[2] = { | ||
3333 | [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) | | ||
3334 | 1 << (OP_EXCHANGE_ID - 32) | | ||
3335 | 1 << (OP_CREATE_SESSION - 32) | | ||
3336 | 1 << (OP_DESTROY_SESSION - 32) | | ||
3337 | 1 << (OP_DESTROY_CLIENTID - 32) | ||
3338 | }; | ||
3339 | |||
3229 | static __be32 | 3340 | static __be32 |
3230 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | 3341 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3231 | struct nfsd4_exchange_id *exid) | 3342 | struct nfsd4_exchange_id *exid) |
@@ -3249,7 +3360,8 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
3249 | 8 /* eir_clientid */ + | 3360 | 8 /* eir_clientid */ + |
3250 | 4 /* eir_sequenceid */ + | 3361 | 4 /* eir_sequenceid */ + |
3251 | 4 /* eir_flags */ + | 3362 | 4 /* eir_flags */ + |
3252 | 4 /* spr_how (SP4_NONE) */ + | 3363 | 4 /* spr_how */ + |
3364 | 8 /* spo_must_enforce, spo_must_allow */ + | ||
3253 | 8 /* so_minor_id */ + | 3365 | 8 /* so_minor_id */ + |
3254 | 4 /* so_major_id.len */ + | 3366 | 4 /* so_major_id.len */ + |
3255 | (XDR_QUADLEN(major_id_sz) * 4) + | 3367 | (XDR_QUADLEN(major_id_sz) * 4) + |
@@ -3261,9 +3373,21 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
3261 | WRITE32(exid->seqid); | 3373 | WRITE32(exid->seqid); |
3262 | WRITE32(exid->flags); | 3374 | WRITE32(exid->flags); |
3263 | 3375 | ||
3264 | /* state_protect4_r. Currently only support SP4_NONE */ | ||
3265 | BUG_ON(exid->spa_how != SP4_NONE); | ||
3266 | WRITE32(exid->spa_how); | 3376 | WRITE32(exid->spa_how); |
3377 | switch (exid->spa_how) { | ||
3378 | case SP4_NONE: | ||
3379 | break; | ||
3380 | case SP4_MACH_CRED: | ||
3381 | /* spo_must_enforce bitmap: */ | ||
3382 | WRITE32(2); | ||
3383 | WRITE32(nfs4_minimal_spo_must_enforce[0]); | ||
3384 | WRITE32(nfs4_minimal_spo_must_enforce[1]); | ||
3385 | /* empty spo_must_allow bitmap: */ | ||
3386 | WRITE32(0); | ||
3387 | break; | ||
3388 | default: | ||
3389 | WARN_ON_ONCE(1); | ||
3390 | } | ||
3267 | 3391 | ||
3268 | /* The server_owner struct */ | 3392 | /* The server_owner struct */ |
3269 | WRITE64(minor_id); /* Minor id */ | 3393 | WRITE64(minor_id); /* Minor id */ |
@@ -3635,13 +3759,17 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3635 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; | 3759 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; |
3636 | BUG_ON(iov->iov_len > PAGE_SIZE); | 3760 | BUG_ON(iov->iov_len > PAGE_SIZE); |
3637 | if (nfsd4_has_session(cs)) { | 3761 | if (nfsd4_has_session(cs)) { |
3762 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3763 | struct nfs4_client *clp = cs->session->se_client; | ||
3638 | if (cs->status != nfserr_replay_cache) { | 3764 | if (cs->status != nfserr_replay_cache) { |
3639 | nfsd4_store_cache_entry(resp); | 3765 | nfsd4_store_cache_entry(resp); |
3640 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; | 3766 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; |
3641 | } | 3767 | } |
3642 | /* Renew the clientid on success and on replay */ | 3768 | /* Renew the clientid on success and on replay */ |
3643 | put_client_renew(cs->session->se_client); | 3769 | spin_lock(&nn->client_lock); |
3644 | nfsd4_put_session(cs->session); | 3770 | nfsd4_put_session(cs->session); |
3771 | spin_unlock(&nn->client_lock); | ||
3772 | put_client_renew(clp); | ||
3645 | } | 3773 | } |
3646 | return 1; | 3774 | return 1; |
3647 | } | 3775 | } |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 07a473fd49bc..30f34ab02137 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -24,7 +24,7 @@ | |||
24 | /* | 24 | /* |
25 | * nfsd version | 25 | * nfsd version |
26 | */ | 26 | */ |
27 | #define NFSD_SUPPORTED_MINOR_VERSION 1 | 27 | #define NFSD_SUPPORTED_MINOR_VERSION 2 |
28 | /* | 28 | /* |
29 | * Maximum blocksizes supported by daemon under various circumstances. | 29 | * Maximum blocksizes supported by daemon under various circumstances. |
30 | */ | 30 | */ |
@@ -53,7 +53,6 @@ struct readdir_cd { | |||
53 | extern struct svc_program nfsd_program; | 53 | extern struct svc_program nfsd_program; |
54 | extern struct svc_version nfsd_version2, nfsd_version3, | 54 | extern struct svc_version nfsd_version2, nfsd_version3, |
55 | nfsd_version4; | 55 | nfsd_version4; |
56 | extern u32 nfsd_supported_minorversion; | ||
57 | extern struct mutex nfsd_mutex; | 56 | extern struct mutex nfsd_mutex; |
58 | extern spinlock_t nfsd_drc_lock; | 57 | extern spinlock_t nfsd_drc_lock; |
59 | extern unsigned long nfsd_drc_max_mem; | 58 | extern unsigned long nfsd_drc_max_mem; |
@@ -243,6 +242,12 @@ void nfsd_lockd_shutdown(void); | |||
243 | #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) | 242 | #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) |
244 | #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) | 243 | #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) |
245 | #define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) | 244 | #define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) |
245 | #define nfserr_partner_notsupp cpu_to_be32(NFS4ERR_PARTNER_NOTSUPP) | ||
246 | #define nfserr_partner_no_auth cpu_to_be32(NFS4ERR_PARTNER_NO_AUTH) | ||
247 | #define nfserr_metadata_notsupp cpu_to_be32(NFS4ERR_METADATA_NOTSUPP) | ||
248 | #define nfserr_offload_denied cpu_to_be32(NFS4ERR_OFFLOAD_DENIED) | ||
249 | #define nfserr_wrong_lfs cpu_to_be32(NFS4ERR_WRONG_LFS) | ||
250 | #define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL) | ||
246 | 251 | ||
247 | /* error codes for internal use */ | 252 | /* error codes for internal use */ |
248 | /* if a request fails due to kmalloc failure, it gets dropped. | 253 | /* if a request fails due to kmalloc failure, it gets dropped. |
@@ -322,6 +327,13 @@ void nfsd_lockd_shutdown(void); | |||
322 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ | 327 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ |
323 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) | 328 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) |
324 | 329 | ||
330 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
331 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ | ||
332 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL) | ||
333 | #else | ||
334 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0 | ||
335 | #endif | ||
336 | |||
325 | static inline u32 nfsd_suppattrs0(u32 minorversion) | 337 | static inline u32 nfsd_suppattrs0(u32 minorversion) |
326 | { | 338 | { |
327 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 | 339 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 |
@@ -336,8 +348,11 @@ static inline u32 nfsd_suppattrs1(u32 minorversion) | |||
336 | 348 | ||
337 | static inline u32 nfsd_suppattrs2(u32 minorversion) | 349 | static inline u32 nfsd_suppattrs2(u32 minorversion) |
338 | { | 350 | { |
339 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2 | 351 | switch (minorversion) { |
340 | : NFSD4_SUPPORTED_ATTRS_WORD2; | 352 | default: return NFSD4_2_SUPPORTED_ATTRS_WORD2; |
353 | case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2; | ||
354 | case 0: return NFSD4_SUPPORTED_ATTRS_WORD2; | ||
355 | } | ||
341 | } | 356 | } |
342 | 357 | ||
343 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ | 358 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ |
@@ -350,7 +365,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) | |||
350 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ | 365 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ |
351 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ | 366 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ |
352 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 367 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
368 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
369 | #define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL | ||
370 | #else | ||
353 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 | 371 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 |
372 | #endif | ||
354 | 373 | ||
355 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ | 374 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ |
356 | NFSD_WRITEABLE_ATTRS_WORD0 | 375 | NFSD_WRITEABLE_ATTRS_WORD0 |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 262df5ccbf59..760c85a6f534 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -116,7 +116,10 @@ struct svc_program nfsd_program = { | |||
116 | 116 | ||
117 | }; | 117 | }; |
118 | 118 | ||
119 | u32 nfsd_supported_minorversion; | 119 | static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = { |
120 | [0] = 1, | ||
121 | [1] = 1, | ||
122 | }; | ||
120 | 123 | ||
121 | int nfsd_vers(int vers, enum vers_op change) | 124 | int nfsd_vers(int vers, enum vers_op change) |
122 | { | 125 | { |
@@ -151,15 +154,13 @@ int nfsd_minorversion(u32 minorversion, enum vers_op change) | |||
151 | return -1; | 154 | return -1; |
152 | switch(change) { | 155 | switch(change) { |
153 | case NFSD_SET: | 156 | case NFSD_SET: |
154 | nfsd_supported_minorversion = minorversion; | 157 | nfsd_supported_minorversions[minorversion] = true; |
155 | break; | 158 | break; |
156 | case NFSD_CLEAR: | 159 | case NFSD_CLEAR: |
157 | if (minorversion == 0) | 160 | nfsd_supported_minorversions[minorversion] = false; |
158 | return -1; | ||
159 | nfsd_supported_minorversion = minorversion - 1; | ||
160 | break; | 161 | break; |
161 | case NFSD_TEST: | 162 | case NFSD_TEST: |
162 | return minorversion <= nfsd_supported_minorversion; | 163 | return nfsd_supported_minorversions[minorversion]; |
163 | case NFSD_AVAIL: | 164 | case NFSD_AVAIL: |
164 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; | 165 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; |
165 | } | 166 | } |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 274e2a114e05..424d8f5f2317 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -246,6 +246,7 @@ struct nfs4_client { | |||
246 | nfs4_verifier cl_verifier; /* generated by client */ | 246 | nfs4_verifier cl_verifier; /* generated by client */ |
247 | time_t cl_time; /* time of last lease renewal */ | 247 | time_t cl_time; /* time of last lease renewal */ |
248 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 248 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
249 | bool cl_mach_cred; /* SP4_MACH_CRED in force */ | ||
249 | struct svc_cred cl_cred; /* setclientid principal */ | 250 | struct svc_cred cl_cred; /* setclientid principal */ |
250 | clientid_t cl_clientid; /* generated by server */ | 251 | clientid_t cl_clientid; /* generated by server */ |
251 | nfs4_verifier cl_confirm; /* generated by server */ | 252 | nfs4_verifier cl_confirm; /* generated by server */ |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 84ce601d8063..c827acb0e943 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <linux/exportfs.h> | 29 | #include <linux/exportfs.h> |
30 | #include <linux/writeback.h> | 30 | #include <linux/writeback.h> |
31 | #include <linux/security.h> | ||
31 | 32 | ||
32 | #ifdef CONFIG_NFSD_V3 | 33 | #ifdef CONFIG_NFSD_V3 |
33 | #include "xdr3.h" | 34 | #include "xdr3.h" |
@@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry) | |||
621 | return 0; | 622 | return 0; |
622 | return 1; | 623 | return 1; |
623 | } | 624 | } |
625 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
626 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
627 | struct xdr_netobj *label) | ||
628 | { | ||
629 | __be32 error; | ||
630 | int host_error; | ||
631 | struct dentry *dentry; | ||
632 | |||
633 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); | ||
634 | if (error) | ||
635 | return error; | ||
636 | |||
637 | dentry = fhp->fh_dentry; | ||
638 | |||
639 | mutex_lock(&dentry->d_inode->i_mutex); | ||
640 | host_error = security_inode_setsecctx(dentry, label->data, label->len); | ||
641 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
642 | return nfserrno(host_error); | ||
643 | } | ||
644 | #else | ||
645 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
646 | struct xdr_netobj *label) | ||
647 | { | ||
648 | return nfserr_notsupp; | ||
649 | } | ||
650 | #endif | ||
651 | |||
624 | #endif /* defined(CONFIG_NFSD_V4) */ | 652 | #endif /* defined(CONFIG_NFSD_V4) */ |
625 | 653 | ||
626 | #ifdef CONFIG_NFSD_V3 | 654 | #ifdef CONFIG_NFSD_V3 |
@@ -802,9 +830,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |||
802 | flags = O_WRONLY|O_LARGEFILE; | 830 | flags = O_WRONLY|O_LARGEFILE; |
803 | } | 831 | } |
804 | *filp = dentry_open(&path, flags, current_cred()); | 832 | *filp = dentry_open(&path, flags, current_cred()); |
805 | if (IS_ERR(*filp)) | 833 | if (IS_ERR(*filp)) { |
806 | host_err = PTR_ERR(*filp); | 834 | host_err = PTR_ERR(*filp); |
807 | else { | 835 | *filp = NULL; |
836 | } else { | ||
808 | host_err = ima_file_check(*filp, may_flags); | 837 | host_err = ima_file_check(*filp, may_flags); |
809 | 838 | ||
810 | if (may_flags & NFSD_MAY_64BIT_COOKIE) | 839 | if (may_flags & NFSD_MAY_64BIT_COOKIE) |
@@ -1912,6 +1941,7 @@ struct buffered_dirent { | |||
1912 | }; | 1941 | }; |
1913 | 1942 | ||
1914 | struct readdir_data { | 1943 | struct readdir_data { |
1944 | struct dir_context ctx; | ||
1915 | char *dirent; | 1945 | char *dirent; |
1916 | size_t used; | 1946 | size_t used; |
1917 | int full; | 1947 | int full; |
@@ -1943,13 +1973,15 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen, | |||
1943 | static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, | 1973 | static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, |
1944 | struct readdir_cd *cdp, loff_t *offsetp) | 1974 | struct readdir_cd *cdp, loff_t *offsetp) |
1945 | { | 1975 | { |
1946 | struct readdir_data buf; | ||
1947 | struct buffered_dirent *de; | 1976 | struct buffered_dirent *de; |
1948 | int host_err; | 1977 | int host_err; |
1949 | int size; | 1978 | int size; |
1950 | loff_t offset; | 1979 | loff_t offset; |
1980 | struct readdir_data buf = { | ||
1981 | .ctx.actor = nfsd_buffered_filldir, | ||
1982 | .dirent = (void *)__get_free_page(GFP_KERNEL) | ||
1983 | }; | ||
1951 | 1984 | ||
1952 | buf.dirent = (void *)__get_free_page(GFP_KERNEL); | ||
1953 | if (!buf.dirent) | 1985 | if (!buf.dirent) |
1954 | return nfserrno(-ENOMEM); | 1986 | return nfserrno(-ENOMEM); |
1955 | 1987 | ||
@@ -1963,7 +1995,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, | |||
1963 | buf.used = 0; | 1995 | buf.used = 0; |
1964 | buf.full = 0; | 1996 | buf.full = 0; |
1965 | 1997 | ||
1966 | host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf); | 1998 | host_err = iterate_dir(file, &buf.ctx); |
1967 | if (buf.full) | 1999 | if (buf.full) |
1968 | host_err = 0; | 2000 | host_err = 0; |
1969 | 2001 | ||
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 5b5894159f22..a4be2e389670 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -39,7 +39,6 @@ | |||
39 | typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); | 39 | typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); |
40 | 40 | ||
41 | /* nfsd/vfs.c */ | 41 | /* nfsd/vfs.c */ |
42 | int fh_lock_parent(struct svc_fh *, struct dentry *); | ||
43 | int nfsd_racache_init(int); | 42 | int nfsd_racache_init(int); |
44 | void nfsd_racache_shutdown(void); | 43 | void nfsd_racache_shutdown(void); |
45 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | 44 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, |
@@ -56,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *); | |||
56 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, | 55 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, |
57 | struct nfs4_acl *); | 56 | struct nfs4_acl *); |
58 | int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); | 57 | int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); |
58 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, | ||
59 | struct xdr_netobj *); | ||
59 | #endif /* CONFIG_NFSD_V4 */ | 60 | #endif /* CONFIG_NFSD_V4 */ |
60 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, | 61 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, |
61 | char *name, int len, struct iattr *attrs, | 62 | char *name, int len, struct iattr *attrs, |
@@ -92,17 +93,13 @@ __be32 nfsd_remove(struct svc_rqst *, | |||
92 | struct svc_fh *, char *, int); | 93 | struct svc_fh *, char *, int); |
93 | __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, | 94 | __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, |
94 | char *name, int len); | 95 | char *name, int len); |
95 | int nfsd_truncate(struct svc_rqst *, struct svc_fh *, | ||
96 | unsigned long size); | ||
97 | __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, | 96 | __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, |
98 | loff_t *, struct readdir_cd *, filldir_t); | 97 | loff_t *, struct readdir_cd *, filldir_t); |
99 | __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, | 98 | __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, |
100 | struct kstatfs *, int access); | 99 | struct kstatfs *, int access); |
101 | 100 | ||
102 | int nfsd_notify_change(struct inode *, struct iattr *); | ||
103 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, | 101 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, |
104 | struct dentry *, int); | 102 | struct dentry *, int); |
105 | int nfsd_sync_dir(struct dentry *dp); | ||
106 | 103 | ||
107 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 104 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
108 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); | 105 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 3b271d2092b6..b3ed6446ed8e 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "state.h" | 40 | #include "state.h" |
41 | #include "nfsd.h" | 41 | #include "nfsd.h" |
42 | 42 | ||
43 | #define NFSD4_MAX_SEC_LABEL_LEN 2048 | ||
43 | #define NFSD4_MAX_TAGLEN 128 | 44 | #define NFSD4_MAX_TAGLEN 128 |
44 | #define XDR_LEN(n) (((n) + 3) & ~3) | 45 | #define XDR_LEN(n) (((n) + 3) & ~3) |
45 | 46 | ||
@@ -118,6 +119,7 @@ struct nfsd4_create { | |||
118 | struct iattr cr_iattr; /* request */ | 119 | struct iattr cr_iattr; /* request */ |
119 | struct nfsd4_change_info cr_cinfo; /* response */ | 120 | struct nfsd4_change_info cr_cinfo; /* response */ |
120 | struct nfs4_acl *cr_acl; | 121 | struct nfs4_acl *cr_acl; |
122 | struct xdr_netobj cr_label; | ||
121 | }; | 123 | }; |
122 | #define cr_linklen u.link.namelen | 124 | #define cr_linklen u.link.namelen |
123 | #define cr_linkname u.link.name | 125 | #define cr_linkname u.link.name |
@@ -246,6 +248,7 @@ struct nfsd4_open { | |||
246 | struct nfs4_file *op_file; /* used during processing */ | 248 | struct nfs4_file *op_file; /* used during processing */ |
247 | struct nfs4_ol_stateid *op_stp; /* used during processing */ | 249 | struct nfs4_ol_stateid *op_stp; /* used during processing */ |
248 | struct nfs4_acl *op_acl; | 250 | struct nfs4_acl *op_acl; |
251 | struct xdr_netobj op_label; | ||
249 | }; | 252 | }; |
250 | #define op_iattr iattr | 253 | #define op_iattr iattr |
251 | 254 | ||
@@ -330,6 +333,7 @@ struct nfsd4_setattr { | |||
330 | u32 sa_bmval[3]; /* request */ | 333 | u32 sa_bmval[3]; /* request */ |
331 | struct iattr sa_iattr; /* request */ | 334 | struct iattr sa_iattr; /* request */ |
332 | struct nfs4_acl *sa_acl; | 335 | struct nfs4_acl *sa_acl; |
336 | struct xdr_netobj sa_label; | ||
333 | }; | 337 | }; |
334 | 338 | ||
335 | struct nfsd4_setclientid { | 339 | struct nfsd4_setclientid { |