diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-31 18:41:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-31 18:41:02 -0500 |
commit | 0fd08c5545a806c960a6597fae4a2e656eb7ead9 (patch) | |
tree | 027dfcc65f600afe6a4b19ab72c472fe3f0f24fa /fs | |
parent | 7921127e297ea203b794c4a1c3ef3eb0ee52acbf (diff) | |
parent | d1205f87bbb8040c1408bbd9e0a720310b2b0b9b (diff) |
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
NFS: NFSv4 readdir loses entries
NFS: Micro-optimize nfs4_decode_dirent()
NFS: Fix an NFS client lockdep issue
NFS construct consistent co_ownerid for v4.1
NFS: nfs_wcc_update_inode() should set nfsi->attr_gencount
NFS improve pnfs_put_deviceid_cache debug print
NFS fix cb_sequence error processing
NFS do not find client in NFSv4 pg_authenticate
NLM: Fix "kernel BUG at fs/lockd/host.c:417!" or ".../host.c:283!"
NFS: Prevent memory allocation failure in nfsacl_encode()
NFS: nfsacl_{encode,decode} should return signed integer
NFS: Fix "kernel BUG at fs/nfs/nfs3xdr.c:1338!"
NFS: Fix "kernel BUG at fs/aio.c:554!"
NFS4: Avoid potential NULL pointer dereference in decode_and_add_ds().
NFS: fix handling of malloc failure during nfs_flush_multi()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/lockd/host.c | 9 | ||||
-rw-r--r-- | fs/nfs/callback.c | 109 | ||||
-rw-r--r-- | fs/nfs/callback.h | 4 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 12 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 5 | ||||
-rw-r--r-- | fs/nfs/client.c | 15 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 6 | ||||
-rw-r--r-- | fs/nfs/direct.c | 34 | ||||
-rw-r--r-- | fs/nfs/inode.c | 26 | ||||
-rw-r--r-- | fs/nfs/internal.h | 3 | ||||
-rw-r--r-- | fs/nfs/nfs3acl.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 5 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 9 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 30 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 9 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 2 | ||||
-rw-r--r-- | fs/nfs_common/nfsacl.c | 54 | ||||
-rw-r--r-- | fs/posix_acl.c | 17 |
20 files changed, 170 insertions, 191 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 5f1bcb2f06f3..b7c99bfb3da6 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -520,7 +520,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, | |||
520 | struct nsm_handle *nsm, | 520 | struct nsm_handle *nsm, |
521 | const struct nlm_reboot *info) | 521 | const struct nlm_reboot *info) |
522 | { | 522 | { |
523 | struct nlm_host *host = NULL; | 523 | struct nlm_host *host; |
524 | struct hlist_head *chain; | 524 | struct hlist_head *chain; |
525 | struct hlist_node *pos; | 525 | struct hlist_node *pos; |
526 | 526 | ||
@@ -532,12 +532,13 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, | |||
532 | host->h_state++; | 532 | host->h_state++; |
533 | 533 | ||
534 | nlm_get_host(host); | 534 | nlm_get_host(host); |
535 | goto out; | 535 | mutex_unlock(&nlm_host_mutex); |
536 | return host; | ||
536 | } | 537 | } |
537 | } | 538 | } |
538 | out: | 539 | |
539 | mutex_unlock(&nlm_host_mutex); | 540 | mutex_unlock(&nlm_host_mutex); |
540 | return host; | 541 | return NULL; |
541 | } | 542 | } |
542 | 543 | ||
543 | /** | 544 | /** |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 199016528fcb..e3d294269058 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -135,33 +135,6 @@ out_err: | |||
135 | 135 | ||
136 | #if defined(CONFIG_NFS_V4_1) | 136 | #if defined(CONFIG_NFS_V4_1) |
137 | /* | 137 | /* |
138 | * * CB_SEQUENCE operations will fail until the callback sessionid is set. | ||
139 | * */ | ||
140 | int nfs4_set_callback_sessionid(struct nfs_client *clp) | ||
141 | { | ||
142 | struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv; | ||
143 | struct nfs4_sessionid *bc_sid; | ||
144 | |||
145 | if (!serv->sv_bc_xprt) | ||
146 | return -EINVAL; | ||
147 | |||
148 | /* on success freed in xprt_free */ | ||
149 | bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL); | ||
150 | if (!bc_sid) | ||
151 | return -ENOMEM; | ||
152 | memcpy(bc_sid->data, &clp->cl_session->sess_id.data, | ||
153 | NFS4_MAX_SESSIONID_LEN); | ||
154 | spin_lock_bh(&serv->sv_cb_lock); | ||
155 | serv->sv_bc_xprt->xpt_bc_sid = bc_sid; | ||
156 | spin_unlock_bh(&serv->sv_cb_lock); | ||
157 | dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__, | ||
158 | ((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1], | ||
159 | ((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3], | ||
160 | serv->sv_bc_xprt); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * The callback service for NFSv4.1 callbacks | 138 | * The callback service for NFSv4.1 callbacks |
166 | */ | 139 | */ |
167 | static int | 140 | static int |
@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | |||
266 | struct nfs_callback_data *cb_info) | 239 | struct nfs_callback_data *cb_info) |
267 | { | 240 | { |
268 | } | 241 | } |
269 | int nfs4_set_callback_sessionid(struct nfs_client *clp) | ||
270 | { | ||
271 | return 0; | ||
272 | } | ||
273 | #endif /* CONFIG_NFS_V4_1 */ | 242 | #endif /* CONFIG_NFS_V4_1 */ |
274 | 243 | ||
275 | /* | 244 | /* |
@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion) | |||
359 | mutex_unlock(&nfs_callback_mutex); | 328 | mutex_unlock(&nfs_callback_mutex); |
360 | } | 329 | } |
361 | 330 | ||
362 | static int check_gss_callback_principal(struct nfs_client *clp, | 331 | /* Boolean check of RPC_AUTH_GSS principal */ |
363 | struct svc_rqst *rqstp) | 332 | int |
333 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | ||
364 | { | 334 | { |
365 | struct rpc_clnt *r = clp->cl_rpcclient; | 335 | struct rpc_clnt *r = clp->cl_rpcclient; |
366 | char *p = svc_gss_principal(rqstp); | 336 | char *p = svc_gss_principal(rqstp); |
367 | 337 | ||
338 | if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) | ||
339 | return 1; | ||
340 | |||
368 | /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ | 341 | /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ |
369 | if (clp->cl_minorversion != 0) | 342 | if (clp->cl_minorversion != 0) |
370 | return SVC_DROP; | 343 | return 0; |
371 | /* | 344 | /* |
372 | * It might just be a normal user principal, in which case | 345 | * It might just be a normal user principal, in which case |
373 | * userspace won't bother to tell us the name at all. | 346 | * userspace won't bother to tell us the name at all. |
374 | */ | 347 | */ |
375 | if (p == NULL) | 348 | if (p == NULL) |
376 | return SVC_DENIED; | 349 | return 0; |
377 | 350 | ||
378 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ | 351 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ |
379 | 352 | ||
380 | if (memcmp(p, "nfs@", 4) != 0) | 353 | if (memcmp(p, "nfs@", 4) != 0) |
381 | return SVC_DENIED; | 354 | return 0; |
382 | p += 4; | 355 | p += 4; |
383 | if (strcmp(p, r->cl_server) != 0) | 356 | if (strcmp(p, r->cl_server) != 0) |
384 | return SVC_DENIED; | 357 | return 0; |
385 | return SVC_OK; | 358 | return 1; |
386 | } | 359 | } |
387 | 360 | ||
388 | /* pg_authenticate method helper */ | 361 | /* |
389 | static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp) | 362 | * pg_authenticate method for nfsv4 callback threads. |
390 | { | 363 | * |
391 | struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp); | 364 | * The authflavor has been negotiated, so an incorrect flavor is a server |
392 | int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0; | 365 | * bug. Drop packets with incorrect authflavor. |
393 | 366 | * | |
394 | dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc); | 367 | * All other checking done after NFS decoding where the nfs_client can be |
395 | if (svc_is_backchannel(rqstp)) | 368 | * found in nfs4_callback_compound |
396 | /* Sessionid (usually) set after CB_NULL ping */ | 369 | */ |
397 | return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid, | ||
398 | is_cb_compound); | ||
399 | else | ||
400 | /* No callback identifier in pg_authenticate */ | ||
401 | return nfs4_find_client_no_ident(svc_addr(rqstp)); | ||
402 | } | ||
403 | |||
404 | /* pg_authenticate method for nfsv4 callback threads. */ | ||
405 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 370 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
406 | { | 371 | { |
407 | struct nfs_client *clp; | ||
408 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | ||
409 | int ret = SVC_OK; | ||
410 | |||
411 | /* Don't talk to strangers */ | ||
412 | clp = nfs_cb_find_client(rqstp); | ||
413 | if (clp == NULL) | ||
414 | return SVC_DROP; | ||
415 | |||
416 | dprintk("%s: %s NFSv4 callback!\n", __func__, | ||
417 | svc_print_addr(rqstp, buf, sizeof(buf))); | ||
418 | |||
419 | switch (rqstp->rq_authop->flavour) { | 372 | switch (rqstp->rq_authop->flavour) { |
420 | case RPC_AUTH_NULL: | 373 | case RPC_AUTH_NULL: |
421 | if (rqstp->rq_proc != CB_NULL) | 374 | if (rqstp->rq_proc != CB_NULL) |
422 | ret = SVC_DENIED; | 375 | return SVC_DROP; |
423 | break; | 376 | break; |
424 | case RPC_AUTH_UNIX: | 377 | case RPC_AUTH_GSS: |
425 | break; | 378 | /* No RPC_AUTH_GSS support yet in NFSv4.1 */ |
426 | case RPC_AUTH_GSS: | 379 | if (svc_is_backchannel(rqstp)) |
427 | ret = check_gss_callback_principal(clp, rqstp); | 380 | return SVC_DROP; |
428 | break; | ||
429 | default: | ||
430 | ret = SVC_DENIED; | ||
431 | } | 381 | } |
432 | nfs_put_client(clp); | 382 | return SVC_OK; |
433 | return ret; | ||
434 | } | 383 | } |
435 | 384 | ||
436 | /* | 385 | /* |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index d3b44f9bd747..46d93ce7311b 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | #ifndef __LINUX_FS_NFS_CALLBACK_H | 8 | #ifndef __LINUX_FS_NFS_CALLBACK_H |
9 | #define __LINUX_FS_NFS_CALLBACK_H | 9 | #define __LINUX_FS_NFS_CALLBACK_H |
10 | #include <linux/sunrpc/svc.h> | ||
10 | 11 | ||
11 | #define NFS4_CALLBACK 0x40000000 | 12 | #define NFS4_CALLBACK 0x40000000 |
12 | #define NFS4_CALLBACK_XDRSIZE 2048 | 13 | #define NFS4_CALLBACK_XDRSIZE 2048 |
@@ -37,7 +38,6 @@ enum nfs4_callback_opnum { | |||
37 | struct cb_process_state { | 38 | struct cb_process_state { |
38 | __be32 drc_status; | 39 | __be32 drc_status; |
39 | struct nfs_client *clp; | 40 | struct nfs_client *clp; |
40 | struct nfs4_sessionid *svc_sid; /* v4.1 callback service sessionid */ | ||
41 | }; | 41 | }; |
42 | 42 | ||
43 | struct cb_compound_hdr_arg { | 43 | struct cb_compound_hdr_arg { |
@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall( | |||
168 | extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); | 168 | extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); |
169 | extern void nfs4_cb_take_slot(struct nfs_client *clp); | 169 | extern void nfs4_cb_take_slot(struct nfs_client *clp); |
170 | #endif /* CONFIG_NFS_V4_1 */ | 170 | #endif /* CONFIG_NFS_V4_1 */ |
171 | 171 | extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *); | |
172 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, | 172 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, |
173 | struct cb_getattrres *res, | 173 | struct cb_getattrres *res, |
174 | struct cb_process_state *cps); | 174 | struct cb_process_state *cps); |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 4bb91cb2620d..89587573fe50 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
373 | { | 373 | { |
374 | struct nfs_client *clp; | 374 | struct nfs_client *clp; |
375 | int i; | 375 | int i; |
376 | __be32 status; | 376 | __be32 status = htonl(NFS4ERR_BADSESSION); |
377 | 377 | ||
378 | cps->clp = NULL; | 378 | cps->clp = NULL; |
379 | 379 | ||
380 | status = htonl(NFS4ERR_BADSESSION); | 380 | clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid); |
381 | /* Incoming session must match the callback session */ | ||
382 | if (memcmp(&args->csa_sessionid, cps->svc_sid, NFS4_MAX_SESSIONID_LEN)) | ||
383 | goto out; | ||
384 | |||
385 | clp = nfs4_find_client_sessionid(args->csa_addr, | ||
386 | &args->csa_sessionid, 1); | ||
387 | if (clp == NULL) | 381 | if (clp == NULL) |
388 | goto out; | 382 | goto out; |
389 | 383 | ||
@@ -414,9 +408,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
414 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | 408 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; |
415 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | 409 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; |
416 | nfs4_cb_take_slot(clp); | 410 | nfs4_cb_take_slot(clp); |
417 | cps->clp = clp; /* put in nfs4_callback_compound */ | ||
418 | 411 | ||
419 | out: | 412 | out: |
413 | cps->clp = clp; /* put in nfs4_callback_compound */ | ||
420 | for (i = 0; i < args->csa_nrclists; i++) | 414 | for (i = 0; i < args->csa_nrclists; i++) |
421 | kfree(args->csa_rclists[i].rcl_refcalls); | 415 | kfree(args->csa_rclists[i].rcl_refcalls); |
422 | kfree(args->csa_rclists); | 416 | kfree(args->csa_rclists); |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 23112c263f81..14e0f9371d14 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
794 | 794 | ||
795 | if (hdr_arg.minorversion == 0) { | 795 | if (hdr_arg.minorversion == 0) { |
796 | cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); | 796 | cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); |
797 | if (!cps.clp) | 797 | if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) |
798 | return rpc_drop_reply; | 798 | return rpc_drop_reply; |
799 | } else | 799 | } |
800 | cps.svc_sid = bc_xprt_sid(rqstp); | ||
801 | 800 | ||
802 | hdr_res.taglen = hdr_arg.taglen; | 801 | hdr_res.taglen = hdr_arg.taglen; |
803 | hdr_res.tag = hdr_arg.tag; | 802 | hdr_res.tag = hdr_arg.tag; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 192f2f860265..bd3ca32879e7 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident) | |||
1206 | * For CB_COMPOUND calls, find a client by IP address, protocol version, | 1206 | * For CB_COMPOUND calls, find a client by IP address, protocol version, |
1207 | * minorversion, and sessionID | 1207 | * minorversion, and sessionID |
1208 | * | 1208 | * |
1209 | * CREATE_SESSION triggers a CB_NULL ping from servers. The callback service | ||
1210 | * sessionid can only be set after the CREATE_SESSION return, so a CB_NULL | ||
1211 | * can arrive before the callback sessionid is set. For CB_NULL calls, | ||
1212 | * find a client by IP address protocol version, and minorversion. | ||
1213 | * | ||
1214 | * Returns NULL if no such client | 1209 | * Returns NULL if no such client |
1215 | */ | 1210 | */ |
1216 | struct nfs_client * | 1211 | struct nfs_client * |
1217 | nfs4_find_client_sessionid(const struct sockaddr *addr, | 1212 | nfs4_find_client_sessionid(const struct sockaddr *addr, |
1218 | struct nfs4_sessionid *sid, int is_cb_compound) | 1213 | struct nfs4_sessionid *sid) |
1219 | { | 1214 | { |
1220 | struct nfs_client *clp; | 1215 | struct nfs_client *clp; |
1221 | 1216 | ||
@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, | |||
1227 | if (!nfs4_has_session(clp)) | 1222 | if (!nfs4_has_session(clp)) |
1228 | continue; | 1223 | continue; |
1229 | 1224 | ||
1230 | /* Match sessionid unless cb_null call*/ | 1225 | /* Match sessionid*/ |
1231 | if (is_cb_compound && (memcmp(clp->cl_session->sess_id.data, | 1226 | if (memcmp(clp->cl_session->sess_id.data, |
1232 | sid->data, NFS4_MAX_SESSIONID_LEN) != 0)) | 1227 | sid->data, NFS4_MAX_SESSIONID_LEN) != 0) |
1233 | continue; | 1228 | continue; |
1234 | 1229 | ||
1235 | atomic_inc(&clp->cl_count); | 1230 | atomic_inc(&clp->cl_count); |
@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, | |||
1244 | 1239 | ||
1245 | struct nfs_client * | 1240 | struct nfs_client * |
1246 | nfs4_find_client_sessionid(const struct sockaddr *addr, | 1241 | nfs4_find_client_sessionid(const struct sockaddr *addr, |
1247 | struct nfs4_sessionid *sid, int is_cb_compound) | 1242 | struct nfs4_sessionid *sid) |
1248 | { | 1243 | { |
1249 | return NULL; | 1244 | return NULL; |
1250 | } | 1245 | } |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 364e4328f392..bbbc6bf5cb2e 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -23,8 +23,6 @@ | |||
23 | 23 | ||
24 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) | 24 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) |
25 | { | 25 | { |
26 | if (delegation->cred) | ||
27 | put_rpccred(delegation->cred); | ||
28 | kfree(delegation); | 26 | kfree(delegation); |
29 | } | 27 | } |
30 | 28 | ||
@@ -37,6 +35,10 @@ static void nfs_free_delegation_callback(struct rcu_head *head) | |||
37 | 35 | ||
38 | static void nfs_free_delegation(struct nfs_delegation *delegation) | 36 | static void nfs_free_delegation(struct nfs_delegation *delegation) |
39 | { | 37 | { |
38 | if (delegation->cred) { | ||
39 | put_rpccred(delegation->cred); | ||
40 | delegation->cred = NULL; | ||
41 | } | ||
40 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | 42 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); |
41 | } | 43 | } |
42 | 44 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e6ace0d93c71..9943a75bb6d1 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -407,15 +407,18 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
407 | pos += vec->iov_len; | 407 | pos += vec->iov_len; |
408 | } | 408 | } |
409 | 409 | ||
410 | /* | ||
411 | * If no bytes were started, return the error, and let the | ||
412 | * generic layer handle the completion. | ||
413 | */ | ||
414 | if (requested_bytes == 0) { | ||
415 | nfs_direct_req_release(dreq); | ||
416 | return result < 0 ? result : -EIO; | ||
417 | } | ||
418 | |||
410 | if (put_dreq(dreq)) | 419 | if (put_dreq(dreq)) |
411 | nfs_direct_complete(dreq); | 420 | nfs_direct_complete(dreq); |
412 | 421 | return 0; | |
413 | if (requested_bytes != 0) | ||
414 | return 0; | ||
415 | |||
416 | if (result < 0) | ||
417 | return result; | ||
418 | return -EIO; | ||
419 | } | 422 | } |
420 | 423 | ||
421 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | 424 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
@@ -841,15 +844,18 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
841 | pos += vec->iov_len; | 844 | pos += vec->iov_len; |
842 | } | 845 | } |
843 | 846 | ||
847 | /* | ||
848 | * If no bytes were started, return the error, and let the | ||
849 | * generic layer handle the completion. | ||
850 | */ | ||
851 | if (requested_bytes == 0) { | ||
852 | nfs_direct_req_release(dreq); | ||
853 | return result < 0 ? result : -EIO; | ||
854 | } | ||
855 | |||
844 | if (put_dreq(dreq)) | 856 | if (put_dreq(dreq)) |
845 | nfs_direct_write_complete(dreq, dreq->inode); | 857 | nfs_direct_write_complete(dreq, dreq->inode); |
846 | 858 | return 0; | |
847 | if (requested_bytes != 0) | ||
848 | return 0; | ||
849 | |||
850 | if (result < 0) | ||
851 | return result; | ||
852 | return -EIO; | ||
853 | } | 859 | } |
854 | 860 | ||
855 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | 861 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d8512423ba72..1cc600e77bb4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -881,9 +881,10 @@ out: | |||
881 | return ret; | 881 | return ret; |
882 | } | 882 | } |
883 | 883 | ||
884 | static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | 884 | static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) |
885 | { | 885 | { |
886 | struct nfs_inode *nfsi = NFS_I(inode); | 886 | struct nfs_inode *nfsi = NFS_I(inode); |
887 | unsigned long ret = 0; | ||
887 | 888 | ||
888 | if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE) | 889 | if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE) |
889 | && (fattr->valid & NFS_ATTR_FATTR_CHANGE) | 890 | && (fattr->valid & NFS_ATTR_FATTR_CHANGE) |
@@ -891,25 +892,32 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
891 | nfsi->change_attr = fattr->change_attr; | 892 | nfsi->change_attr = fattr->change_attr; |
892 | if (S_ISDIR(inode->i_mode)) | 893 | if (S_ISDIR(inode->i_mode)) |
893 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 894 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
895 | ret |= NFS_INO_INVALID_ATTR; | ||
894 | } | 896 | } |
895 | /* If we have atomic WCC data, we may update some attributes */ | 897 | /* If we have atomic WCC data, we may update some attributes */ |
896 | if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME) | 898 | if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME) |
897 | && (fattr->valid & NFS_ATTR_FATTR_CTIME) | 899 | && (fattr->valid & NFS_ATTR_FATTR_CTIME) |
898 | && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) | 900 | && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) { |
899 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 901 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); |
902 | ret |= NFS_INO_INVALID_ATTR; | ||
903 | } | ||
900 | 904 | ||
901 | if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME) | 905 | if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME) |
902 | && (fattr->valid & NFS_ATTR_FATTR_MTIME) | 906 | && (fattr->valid & NFS_ATTR_FATTR_MTIME) |
903 | && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { | 907 | && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { |
904 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 908 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
905 | if (S_ISDIR(inode->i_mode)) | 909 | if (S_ISDIR(inode->i_mode)) |
906 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 910 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
911 | ret |= NFS_INO_INVALID_ATTR; | ||
907 | } | 912 | } |
908 | if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) | 913 | if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) |
909 | && (fattr->valid & NFS_ATTR_FATTR_SIZE) | 914 | && (fattr->valid & NFS_ATTR_FATTR_SIZE) |
910 | && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) | 915 | && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) |
911 | && nfsi->npages == 0) | 916 | && nfsi->npages == 0) { |
912 | i_size_write(inode, nfs_size_to_loff_t(fattr->size)); | 917 | i_size_write(inode, nfs_size_to_loff_t(fattr->size)); |
918 | ret |= NFS_INO_INVALID_ATTR; | ||
919 | } | ||
920 | return ret; | ||
913 | } | 921 | } |
914 | 922 | ||
915 | /** | 923 | /** |
@@ -1223,7 +1231,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1223 | | NFS_INO_REVAL_PAGECACHE); | 1231 | | NFS_INO_REVAL_PAGECACHE); |
1224 | 1232 | ||
1225 | /* Do atomic weak cache consistency updates */ | 1233 | /* Do atomic weak cache consistency updates */ |
1226 | nfs_wcc_update_inode(inode, fattr); | 1234 | invalid |= nfs_wcc_update_inode(inode, fattr); |
1227 | 1235 | ||
1228 | /* More cache consistency checks */ | 1236 | /* More cache consistency checks */ |
1229 | if (fattr->valid & NFS_ATTR_FATTR_CHANGE) { | 1237 | if (fattr->valid & NFS_ATTR_FATTR_CHANGE) { |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 4644f04b4b46..cf9fdbdabc67 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *); | |||
133 | extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *); | 133 | extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *); |
134 | extern struct nfs_client *nfs4_find_client_ident(int); | 134 | extern struct nfs_client *nfs4_find_client_ident(int); |
135 | extern struct nfs_client * | 135 | extern struct nfs_client * |
136 | nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *, | 136 | nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *); |
137 | int); | ||
138 | extern struct nfs_server *nfs_create_server( | 137 | extern struct nfs_server *nfs_create_server( |
139 | const struct nfs_parsed_mount_data *, | 138 | const struct nfs_parsed_mount_data *, |
140 | struct nfs_fh *); | 139 | struct nfs_fh *); |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 9f88c5f4c7e2..274342771655 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -311,8 +311,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
311 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | 311 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) |
312 | goto out; | 312 | goto out; |
313 | 313 | ||
314 | /* We are doing this here, because XDR marshalling can only | 314 | /* We are doing this here because XDR marshalling does not |
315 | return -ENOMEM. */ | 315 | * return any results, it BUGs. */ |
316 | status = -ENOSPC; | 316 | status = -ENOSPC; |
317 | if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) | 317 | if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) |
318 | goto out; | 318 | goto out; |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 01c5e8b1941d..183c6b123d0f 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -1328,10 +1328,13 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, | |||
1328 | 1328 | ||
1329 | encode_nfs_fh3(xdr, NFS_FH(args->inode)); | 1329 | encode_nfs_fh3(xdr, NFS_FH(args->inode)); |
1330 | encode_uint32(xdr, args->mask); | 1330 | encode_uint32(xdr, args->mask); |
1331 | |||
1332 | base = req->rq_slen; | ||
1331 | if (args->npages != 0) | 1333 | if (args->npages != 0) |
1332 | xdr_write_pages(xdr, args->pages, 0, args->len); | 1334 | xdr_write_pages(xdr, args->pages, 0, args->len); |
1335 | else | ||
1336 | xdr_reserve_space(xdr, NFS_ACL_INLINE_BUFSIZE); | ||
1333 | 1337 | ||
1334 | base = req->rq_slen; | ||
1335 | error = nfsacl_encode(xdr->buf, base, args->inode, | 1338 | error = nfsacl_encode(xdr->buf, base, args->inode, |
1336 | (args->mask & NFS_ACL) ? | 1339 | (args->mask & NFS_ACL) ? |
1337 | args->acl_access : NULL, 1, 0); | 1340 | args->acl_access : NULL, 1, 0); |
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 51fe64ace55a..f5c9b125e8cc 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -214,7 +214,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
214 | 214 | ||
215 | /* ipv6 length plus port is legal */ | 215 | /* ipv6 length plus port is legal */ |
216 | if (rlen > INET6_ADDRSTRLEN + 8) { | 216 | if (rlen > INET6_ADDRSTRLEN + 8) { |
217 | dprintk("%s Invalid address, length %d\n", __func__, | 217 | dprintk("%s: Invalid address, length %d\n", __func__, |
218 | rlen); | 218 | rlen); |
219 | goto out_err; | 219 | goto out_err; |
220 | } | 220 | } |
@@ -225,6 +225,11 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
225 | /* replace the port dots with dashes for the in4_pton() delimiter*/ | 225 | /* replace the port dots with dashes for the in4_pton() delimiter*/ |
226 | for (i = 0; i < 2; i++) { | 226 | for (i = 0; i < 2; i++) { |
227 | char *res = strrchr(buf, '.'); | 227 | char *res = strrchr(buf, '.'); |
228 | if (!res) { | ||
229 | dprintk("%s: Failed finding expected dots in port\n", | ||
230 | __func__); | ||
231 | goto out_free; | ||
232 | } | ||
228 | *res = '-'; | 233 | *res = '-'; |
229 | } | 234 | } |
230 | 235 | ||
@@ -240,7 +245,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
240 | port = htons((tmp[0] << 8) | (tmp[1])); | 245 | port = htons((tmp[0] << 8) | (tmp[1])); |
241 | 246 | ||
242 | ds = nfs4_pnfs_ds_add(inode, ip_addr, port); | 247 | ds = nfs4_pnfs_ds_add(inode, ip_addr, port); |
243 | dprintk("%s Decoded address and port %s\n", __func__, buf); | 248 | dprintk("%s: Decoded address and port %s\n", __func__, buf); |
244 | out_free: | 249 | out_free: |
245 | kfree(buf); | 250 | kfree(buf); |
246 | out_err: | 251 | out_err: |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9d992b0346e3..78936a8f40ab 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/module.h> | 50 | #include <linux/module.h> |
51 | #include <linux/sunrpc/bc_xprt.h> | 51 | #include <linux/sunrpc/bc_xprt.h> |
52 | #include <linux/xattr.h> | 52 | #include <linux/xattr.h> |
53 | #include <linux/utsname.h> | ||
53 | 54 | ||
54 | #include "nfs4_fs.h" | 55 | #include "nfs4_fs.h" |
55 | #include "delegation.h" | 56 | #include "delegation.h" |
@@ -4572,27 +4573,16 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4572 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | 4573 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); |
4573 | args.verifier = &verifier; | 4574 | args.verifier = &verifier; |
4574 | 4575 | ||
4575 | while (1) { | 4576 | args.id_len = scnprintf(args.id, sizeof(args.id), |
4576 | args.id_len = scnprintf(args.id, sizeof(args.id), | 4577 | "%s/%s.%s/%u", |
4577 | "%s/%s %u", | 4578 | clp->cl_ipaddr, |
4578 | clp->cl_ipaddr, | 4579 | init_utsname()->nodename, |
4579 | rpc_peeraddr2str(clp->cl_rpcclient, | 4580 | init_utsname()->domainname, |
4580 | RPC_DISPLAY_ADDR), | 4581 | clp->cl_rpcclient->cl_auth->au_flavor); |
4581 | clp->cl_id_uniquifier); | ||
4582 | |||
4583 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4584 | |||
4585 | if (status != -NFS4ERR_CLID_INUSE) | ||
4586 | break; | ||
4587 | |||
4588 | if (signalled()) | ||
4589 | break; | ||
4590 | |||
4591 | if (++clp->cl_id_uniquifier == 0) | ||
4592 | break; | ||
4593 | } | ||
4594 | 4582 | ||
4595 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | 4583 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
4584 | if (!status) | ||
4585 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | ||
4596 | dprintk("<-- %s status= %d\n", __func__, status); | 4586 | dprintk("<-- %s status= %d\n", __func__, status); |
4597 | return status; | 4587 | return status; |
4598 | } | 4588 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 2336d532cf66..e6742b57a04c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
232 | status = nfs4_proc_create_session(clp); | 232 | status = nfs4_proc_create_session(clp); |
233 | if (status != 0) | 233 | if (status != 0) |
234 | goto out; | 234 | goto out; |
235 | status = nfs4_set_callback_sessionid(clp); | ||
236 | if (status != 0) { | ||
237 | printk(KERN_WARNING "Sessionid not set. No callback service\n"); | ||
238 | nfs_callback_down(1); | ||
239 | status = 0; | ||
240 | } | ||
241 | nfs41_setup_state_renewal(clp); | 235 | nfs41_setup_state_renewal(clp); |
242 | nfs_mark_client_ready(clp, NFS_CS_READY); | 236 | nfs_mark_client_ready(clp, NFS_CS_READY); |
243 | out: | 237 | out: |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 2ab8e5cb8f59..4e2c168b6ee9 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -6086,11 +6086,11 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6086 | __be32 *p = xdr_inline_decode(xdr, 4); | 6086 | __be32 *p = xdr_inline_decode(xdr, 4); |
6087 | if (unlikely(!p)) | 6087 | if (unlikely(!p)) |
6088 | goto out_overflow; | 6088 | goto out_overflow; |
6089 | if (!ntohl(*p++)) { | 6089 | if (*p == xdr_zero) { |
6090 | p = xdr_inline_decode(xdr, 4); | 6090 | p = xdr_inline_decode(xdr, 4); |
6091 | if (unlikely(!p)) | 6091 | if (unlikely(!p)) |
6092 | goto out_overflow; | 6092 | goto out_overflow; |
6093 | if (!ntohl(*p++)) | 6093 | if (*p == xdr_zero) |
6094 | return -EAGAIN; | 6094 | return -EAGAIN; |
6095 | entry->eof = 1; | 6095 | entry->eof = 1; |
6096 | return -EBADCOOKIE; | 6096 | return -EBADCOOKIE; |
@@ -6101,7 +6101,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6101 | goto out_overflow; | 6101 | goto out_overflow; |
6102 | entry->prev_cookie = entry->cookie; | 6102 | entry->prev_cookie = entry->cookie; |
6103 | p = xdr_decode_hyper(p, &entry->cookie); | 6103 | p = xdr_decode_hyper(p, &entry->cookie); |
6104 | entry->len = ntohl(*p++); | 6104 | entry->len = be32_to_cpup(p); |
6105 | 6105 | ||
6106 | p = xdr_inline_decode(xdr, entry->len); | 6106 | p = xdr_inline_decode(xdr, entry->len); |
6107 | if (unlikely(!p)) | 6107 | if (unlikely(!p)) |
@@ -6132,9 +6132,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6132 | if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) | 6132 | if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) |
6133 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); | 6133 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); |
6134 | 6134 | ||
6135 | if (verify_attr_len(xdr, p, len) < 0) | ||
6136 | goto out_overflow; | ||
6137 | |||
6138 | return 0; | 6135 | return 0; |
6139 | 6136 | ||
6140 | out_overflow: | 6137 | out_overflow: |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index bc4089769735..1b1bc1a0fb0a 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -951,7 +951,7 @@ pnfs_put_deviceid_cache(struct nfs_client *clp) | |||
951 | { | 951 | { |
952 | struct pnfs_deviceid_cache *local = clp->cl_devid_cache; | 952 | struct pnfs_deviceid_cache *local = clp->cl_devid_cache; |
953 | 953 | ||
954 | dprintk("--> %s cl_devid_cache %p\n", __func__, clp->cl_devid_cache); | 954 | dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref)); |
955 | if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) { | 955 | if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) { |
956 | int i; | 956 | int i; |
957 | /* Verify cache is empty */ | 957 | /* Verify cache is empty */ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 10d648ea128b..c8278f4046cb 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -932,7 +932,7 @@ out_bad: | |||
932 | while (!list_empty(&list)) { | 932 | while (!list_empty(&list)) { |
933 | data = list_entry(list.next, struct nfs_write_data, pages); | 933 | data = list_entry(list.next, struct nfs_write_data, pages); |
934 | list_del(&data->pages); | 934 | list_del(&data->pages); |
935 | nfs_writedata_release(data); | 935 | nfs_writedata_free(data); |
936 | } | 936 | } |
937 | nfs_redirty_request(req); | 937 | nfs_redirty_request(req); |
938 | return -ENOMEM; | 938 | return -ENOMEM; |
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index fc1c52571c03..84c27d69d421 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c | |||
@@ -42,6 +42,11 @@ struct nfsacl_encode_desc { | |||
42 | gid_t gid; | 42 | gid_t gid; |
43 | }; | 43 | }; |
44 | 44 | ||
45 | struct nfsacl_simple_acl { | ||
46 | struct posix_acl acl; | ||
47 | struct posix_acl_entry ace[4]; | ||
48 | }; | ||
49 | |||
45 | static int | 50 | static int |
46 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) | 51 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) |
47 | { | 52 | { |
@@ -72,9 +77,20 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) | |||
72 | return 0; | 77 | return 0; |
73 | } | 78 | } |
74 | 79 | ||
75 | unsigned int | 80 | /** |
76 | nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | 81 | * nfsacl_encode - Encode an NFSv3 ACL |
77 | struct posix_acl *acl, int encode_entries, int typeflag) | 82 | * |
83 | * @buf: destination xdr_buf to contain XDR encoded ACL | ||
84 | * @base: byte offset in xdr_buf where XDR'd ACL begins | ||
85 | * @inode: inode of file whose ACL this is | ||
86 | * @acl: posix_acl to encode | ||
87 | * @encode_entries: whether to encode ACEs as well | ||
88 | * @typeflag: ACL type: NFS_ACL_DEFAULT or zero | ||
89 | * | ||
90 | * Returns size of encoded ACL in bytes or a negative errno value. | ||
91 | */ | ||
92 | int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | ||
93 | struct posix_acl *acl, int encode_entries, int typeflag) | ||
78 | { | 94 | { |
79 | int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; | 95 | int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; |
80 | struct nfsacl_encode_desc nfsacl_desc = { | 96 | struct nfsacl_encode_desc nfsacl_desc = { |
@@ -88,17 +104,22 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | |||
88 | .uid = inode->i_uid, | 104 | .uid = inode->i_uid, |
89 | .gid = inode->i_gid, | 105 | .gid = inode->i_gid, |
90 | }; | 106 | }; |
107 | struct nfsacl_simple_acl aclbuf; | ||
91 | int err; | 108 | int err; |
92 | struct posix_acl *acl2 = NULL; | ||
93 | 109 | ||
94 | if (entries > NFS_ACL_MAX_ENTRIES || | 110 | if (entries > NFS_ACL_MAX_ENTRIES || |
95 | xdr_encode_word(buf, base, entries)) | 111 | xdr_encode_word(buf, base, entries)) |
96 | return -EINVAL; | 112 | return -EINVAL; |
97 | if (encode_entries && acl && acl->a_count == 3) { | 113 | if (encode_entries && acl && acl->a_count == 3) { |
98 | /* Fake up an ACL_MASK entry. */ | 114 | struct posix_acl *acl2 = &aclbuf.acl; |
99 | acl2 = posix_acl_alloc(4, GFP_KERNEL); | 115 | |
100 | if (!acl2) | 116 | /* Avoid the use of posix_acl_alloc(). nfsacl_encode() is |
101 | return -ENOMEM; | 117 | * invoked in contexts where a memory allocation failure is |
118 | * fatal. Fortunately this fake ACL is small enough to | ||
119 | * construct on the stack. */ | ||
120 | memset(acl2, 0, sizeof(acl2)); | ||
121 | posix_acl_init(acl2, 4); | ||
122 | |||
102 | /* Insert entries in canonical order: other orders seem | 123 | /* Insert entries in canonical order: other orders seem |
103 | to confuse Solaris VxFS. */ | 124 | to confuse Solaris VxFS. */ |
104 | acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ | 125 | acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ |
@@ -109,8 +130,6 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | |||
109 | nfsacl_desc.acl = acl2; | 130 | nfsacl_desc.acl = acl2; |
110 | } | 131 | } |
111 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); | 132 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); |
112 | if (acl2) | ||
113 | posix_acl_release(acl2); | ||
114 | if (!err) | 133 | if (!err) |
115 | err = 8 + nfsacl_desc.desc.elem_size * | 134 | err = 8 + nfsacl_desc.desc.elem_size * |
116 | nfsacl_desc.desc.array_len; | 135 | nfsacl_desc.desc.array_len; |
@@ -224,9 +243,18 @@ posix_acl_from_nfsacl(struct posix_acl *acl) | |||
224 | return 0; | 243 | return 0; |
225 | } | 244 | } |
226 | 245 | ||
227 | unsigned int | 246 | /** |
228 | nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, | 247 | * nfsacl_decode - Decode an NFSv3 ACL |
229 | struct posix_acl **pacl) | 248 | * |
249 | * @buf: xdr_buf containing XDR'd ACL data to decode | ||
250 | * @base: byte offset in xdr_buf where XDR'd ACL begins | ||
251 | * @aclcnt: count of ACEs in decoded posix_acl | ||
252 | * @pacl: buffer in which to place decoded posix_acl | ||
253 | * | ||
254 | * Returns the length of the decoded ACL in bytes, or a negative errno value. | ||
255 | */ | ||
256 | int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, | ||
257 | struct posix_acl **pacl) | ||
230 | { | 258 | { |
231 | struct nfsacl_decode_desc nfsacl_desc = { | 259 | struct nfsacl_decode_desc nfsacl_desc = { |
232 | .desc = { | 260 | .desc = { |
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 39df95a0ec25..b1cf6bf4b41d 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | 24 | ||
25 | EXPORT_SYMBOL(posix_acl_init); | ||
25 | EXPORT_SYMBOL(posix_acl_alloc); | 26 | EXPORT_SYMBOL(posix_acl_alloc); |
26 | EXPORT_SYMBOL(posix_acl_clone); | 27 | EXPORT_SYMBOL(posix_acl_clone); |
27 | EXPORT_SYMBOL(posix_acl_valid); | 28 | EXPORT_SYMBOL(posix_acl_valid); |
@@ -32,6 +33,16 @@ EXPORT_SYMBOL(posix_acl_chmod_masq); | |||
32 | EXPORT_SYMBOL(posix_acl_permission); | 33 | EXPORT_SYMBOL(posix_acl_permission); |
33 | 34 | ||
34 | /* | 35 | /* |
36 | * Init a fresh posix_acl | ||
37 | */ | ||
38 | void | ||
39 | posix_acl_init(struct posix_acl *acl, int count) | ||
40 | { | ||
41 | atomic_set(&acl->a_refcount, 1); | ||
42 | acl->a_count = count; | ||
43 | } | ||
44 | |||
45 | /* | ||
35 | * Allocate a new ACL with the specified number of entries. | 46 | * Allocate a new ACL with the specified number of entries. |
36 | */ | 47 | */ |
37 | struct posix_acl * | 48 | struct posix_acl * |
@@ -40,10 +51,8 @@ posix_acl_alloc(int count, gfp_t flags) | |||
40 | const size_t size = sizeof(struct posix_acl) + | 51 | const size_t size = sizeof(struct posix_acl) + |
41 | count * sizeof(struct posix_acl_entry); | 52 | count * sizeof(struct posix_acl_entry); |
42 | struct posix_acl *acl = kmalloc(size, flags); | 53 | struct posix_acl *acl = kmalloc(size, flags); |
43 | if (acl) { | 54 | if (acl) |
44 | atomic_set(&acl->a_refcount, 1); | 55 | posix_acl_init(acl, count); |
45 | acl->a_count = count; | ||
46 | } | ||
47 | return acl; | 56 | return acl; |
48 | } | 57 | } |
49 | 58 | ||