diff options
Diffstat (limited to 'fs/nfsd/state.h')
-rw-r--r-- | fs/nfsd/state.h | 174 |
1 files changed, 83 insertions, 91 deletions
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 4eefaf1b42e8..a3cf38476a1b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #ifndef _NFSD4_STATE_H | 35 | #ifndef _NFSD4_STATE_H |
36 | #define _NFSD4_STATE_H | 36 | #define _NFSD4_STATE_H |
37 | 37 | ||
38 | #include <linux/idr.h> | ||
38 | #include <linux/sunrpc/svc_xprt.h> | 39 | #include <linux/sunrpc/svc_xprt.h> |
39 | #include <linux/nfsd/nfsfh.h> | 40 | #include <linux/nfsd/nfsfh.h> |
40 | #include "nfsfh.h" | 41 | #include "nfsfh.h" |
@@ -45,24 +46,20 @@ typedef struct { | |||
45 | } clientid_t; | 46 | } clientid_t; |
46 | 47 | ||
47 | typedef struct { | 48 | typedef struct { |
48 | u32 so_boot; | 49 | clientid_t so_clid; |
49 | u32 so_stateownerid; | 50 | u32 so_id; |
50 | u32 so_fileid; | ||
51 | } stateid_opaque_t; | 51 | } stateid_opaque_t; |
52 | 52 | ||
53 | typedef struct { | 53 | typedef struct { |
54 | u32 si_generation; | 54 | u32 si_generation; |
55 | stateid_opaque_t si_opaque; | 55 | stateid_opaque_t si_opaque; |
56 | } stateid_t; | 56 | } stateid_t; |
57 | #define si_boot si_opaque.so_boot | ||
58 | #define si_stateownerid si_opaque.so_stateownerid | ||
59 | #define si_fileid si_opaque.so_fileid | ||
60 | 57 | ||
61 | #define STATEID_FMT "(%08x/%08x/%08x/%08x)" | 58 | #define STATEID_FMT "(%08x/%08x/%08x/%08x)" |
62 | #define STATEID_VAL(s) \ | 59 | #define STATEID_VAL(s) \ |
63 | (s)->si_boot, \ | 60 | (s)->si_opaque.so_clid.cl_boot, \ |
64 | (s)->si_stateownerid, \ | 61 | (s)->si_opaque.so_clid.cl_id, \ |
65 | (s)->si_fileid, \ | 62 | (s)->si_opaque.so_id, \ |
66 | (s)->si_generation | 63 | (s)->si_generation |
67 | 64 | ||
68 | struct nfsd4_callback { | 65 | struct nfsd4_callback { |
@@ -76,17 +73,27 @@ struct nfsd4_callback { | |||
76 | bool cb_done; | 73 | bool cb_done; |
77 | }; | 74 | }; |
78 | 75 | ||
76 | struct nfs4_stid { | ||
77 | #define NFS4_OPEN_STID 1 | ||
78 | #define NFS4_LOCK_STID 2 | ||
79 | #define NFS4_DELEG_STID 4 | ||
80 | /* For an open stateid kept around *only* to process close replays: */ | ||
81 | #define NFS4_CLOSED_STID 8 | ||
82 | unsigned char sc_type; | ||
83 | stateid_t sc_stateid; | ||
84 | struct nfs4_client *sc_client; | ||
85 | }; | ||
86 | |||
79 | struct nfs4_delegation { | 87 | struct nfs4_delegation { |
88 | struct nfs4_stid dl_stid; /* must be first field */ | ||
80 | struct list_head dl_perfile; | 89 | struct list_head dl_perfile; |
81 | struct list_head dl_perclnt; | 90 | struct list_head dl_perclnt; |
82 | struct list_head dl_recall_lru; /* delegation recalled */ | 91 | struct list_head dl_recall_lru; /* delegation recalled */ |
83 | atomic_t dl_count; /* ref count */ | 92 | atomic_t dl_count; /* ref count */ |
84 | struct nfs4_client *dl_client; | ||
85 | struct nfs4_file *dl_file; | 93 | struct nfs4_file *dl_file; |
86 | u32 dl_type; | 94 | u32 dl_type; |
87 | time_t dl_time; | 95 | time_t dl_time; |
88 | /* For recall: */ | 96 | /* For recall: */ |
89 | stateid_t dl_stateid; | ||
90 | struct knfsd_fh dl_fh; | 97 | struct knfsd_fh dl_fh; |
91 | int dl_retries; | 98 | int dl_retries; |
92 | struct nfsd4_callback dl_recall; | 99 | struct nfsd4_callback dl_recall; |
@@ -104,6 +111,11 @@ struct nfs4_cb_conn { | |||
104 | struct svc_xprt *cb_xprt; /* minorversion 1 only */ | 111 | struct svc_xprt *cb_xprt; /* minorversion 1 only */ |
105 | }; | 112 | }; |
106 | 113 | ||
114 | static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) | ||
115 | { | ||
116 | return container_of(s, struct nfs4_delegation, dl_stid); | ||
117 | } | ||
118 | |||
107 | /* Maximum number of slots per session. 160 is useful for long haul TCP */ | 119 | /* Maximum number of slots per session. 160 is useful for long haul TCP */ |
108 | #define NFSD_MAX_SLOTS_PER_SESSION 160 | 120 | #define NFSD_MAX_SLOTS_PER_SESSION 160 |
109 | /* Maximum number of operations per session compound */ | 121 | /* Maximum number of operations per session compound */ |
@@ -220,6 +232,7 @@ struct nfs4_client { | |||
220 | struct list_head cl_idhash; /* hash by cl_clientid.id */ | 232 | struct list_head cl_idhash; /* hash by cl_clientid.id */ |
221 | struct list_head cl_strhash; /* hash by cl_name */ | 233 | struct list_head cl_strhash; /* hash by cl_name */ |
222 | struct list_head cl_openowners; | 234 | struct list_head cl_openowners; |
235 | struct idr cl_stateids; /* stateid lookup */ | ||
223 | struct list_head cl_delegations; | 236 | struct list_head cl_delegations; |
224 | struct list_head cl_lru; /* tail queue */ | 237 | struct list_head cl_lru; /* tail queue */ |
225 | struct xdr_netobj cl_name; /* id generated by client */ | 238 | struct xdr_netobj cl_name; /* id generated by client */ |
@@ -245,6 +258,7 @@ struct nfs4_client { | |||
245 | #define NFSD4_CB_UP 0 | 258 | #define NFSD4_CB_UP 0 |
246 | #define NFSD4_CB_UNKNOWN 1 | 259 | #define NFSD4_CB_UNKNOWN 1 |
247 | #define NFSD4_CB_DOWN 2 | 260 | #define NFSD4_CB_DOWN 2 |
261 | #define NFSD4_CB_FAULT 3 | ||
248 | int cl_cb_state; | 262 | int cl_cb_state; |
249 | struct nfsd4_callback cl_cb_null; | 263 | struct nfsd4_callback cl_cb_null; |
250 | struct nfsd4_session *cl_cb_session; | 264 | struct nfsd4_session *cl_cb_session; |
@@ -293,6 +307,9 @@ static inline void | |||
293 | update_stateid(stateid_t *stateid) | 307 | update_stateid(stateid_t *stateid) |
294 | { | 308 | { |
295 | stateid->si_generation++; | 309 | stateid->si_generation++; |
310 | /* Wraparound recommendation from 3530bis-13 9.1.3.2: */ | ||
311 | if (stateid->si_generation == 0) | ||
312 | stateid->si_generation = 1; | ||
296 | } | 313 | } |
297 | 314 | ||
298 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: | 315 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: |
@@ -312,49 +329,57 @@ struct nfs4_replay { | |||
312 | __be32 rp_status; | 329 | __be32 rp_status; |
313 | unsigned int rp_buflen; | 330 | unsigned int rp_buflen; |
314 | char *rp_buf; | 331 | char *rp_buf; |
315 | unsigned intrp_allocated; | ||
316 | struct knfsd_fh rp_openfh; | 332 | struct knfsd_fh rp_openfh; |
317 | char rp_ibuf[NFSD4_REPLAY_ISIZE]; | 333 | char rp_ibuf[NFSD4_REPLAY_ISIZE]; |
318 | }; | 334 | }; |
319 | 335 | ||
320 | /* | ||
321 | * nfs4_stateowner can either be an open_owner, or a lock_owner | ||
322 | * | ||
323 | * so_idhash: stateid_hashtbl[] for open owner, lockstateid_hashtbl[] | ||
324 | * for lock_owner | ||
325 | * so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[] | ||
326 | * for lock_owner | ||
327 | * so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client | ||
328 | * struct is reaped. | ||
329 | * so_perfilestate: heads the list of nfs4_stateid (either open or lock) | ||
330 | * and is used to ensure no dangling nfs4_stateid references when we | ||
331 | * release a stateowner. | ||
332 | * so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when | ||
333 | * close is called to reap associated byte-range locks | ||
334 | * so_close_lru: (open) stateowner is placed on this list instead of being | ||
335 | * reaped (when so_perfilestate is empty) to hold the last close replay. | ||
336 | * reaped by laundramat thread after lease period. | ||
337 | */ | ||
338 | struct nfs4_stateowner { | 336 | struct nfs4_stateowner { |
339 | struct kref so_ref; | ||
340 | struct list_head so_idhash; /* hash by so_id */ | ||
341 | struct list_head so_strhash; /* hash by op_name */ | 337 | struct list_head so_strhash; /* hash by op_name */ |
342 | struct list_head so_perclient; | ||
343 | struct list_head so_stateids; | 338 | struct list_head so_stateids; |
344 | struct list_head so_perstateid; /* for lockowners only */ | ||
345 | struct list_head so_close_lru; /* tail queue */ | ||
346 | time_t so_time; /* time of placement on so_close_lru */ | ||
347 | int so_is_open_owner; /* 1=openowner,0=lockowner */ | ||
348 | u32 so_id; | ||
349 | struct nfs4_client * so_client; | 339 | struct nfs4_client * so_client; |
350 | /* after increment in ENCODE_SEQID_OP_TAIL, represents the next | 340 | /* after increment in ENCODE_SEQID_OP_TAIL, represents the next |
351 | * sequence id expected from the client: */ | 341 | * sequence id expected from the client: */ |
352 | u32 so_seqid; | 342 | u32 so_seqid; |
353 | struct xdr_netobj so_owner; /* open owner name */ | 343 | struct xdr_netobj so_owner; /* open owner name */ |
354 | int so_confirmed; /* successful OPEN_CONFIRM? */ | ||
355 | struct nfs4_replay so_replay; | 344 | struct nfs4_replay so_replay; |
345 | bool so_is_open_owner; | ||
356 | }; | 346 | }; |
357 | 347 | ||
348 | struct nfs4_openowner { | ||
349 | struct nfs4_stateowner oo_owner; /* must be first field */ | ||
350 | struct list_head oo_perclient; | ||
351 | /* | ||
352 | * We keep around openowners a little while after last close, | ||
353 | * which saves clients from having to confirm, and allows us to | ||
354 | * handle close replays if they come soon enough. The close_lru | ||
355 | * is a list of such openowners, to be reaped by the laundromat | ||
356 | * thread eventually if they remain unused: | ||
357 | */ | ||
358 | struct list_head oo_close_lru; | ||
359 | struct nfs4_ol_stateid *oo_last_closed_stid; | ||
360 | time_t oo_time; /* time of placement on so_close_lru */ | ||
361 | #define NFS4_OO_CONFIRMED 1 | ||
362 | #define NFS4_OO_PURGE_CLOSE 2 | ||
363 | #define NFS4_OO_NEW 4 | ||
364 | unsigned char oo_flags; | ||
365 | }; | ||
366 | |||
367 | struct nfs4_lockowner { | ||
368 | struct nfs4_stateowner lo_owner; /* must be first element */ | ||
369 | struct list_head lo_perstateid; /* for lockowners only */ | ||
370 | struct list_head lo_list; /* for temporary uses */ | ||
371 | }; | ||
372 | |||
373 | static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so) | ||
374 | { | ||
375 | return container_of(so, struct nfs4_openowner, oo_owner); | ||
376 | } | ||
377 | |||
378 | static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) | ||
379 | { | ||
380 | return container_of(so, struct nfs4_lockowner, lo_owner); | ||
381 | } | ||
382 | |||
358 | /* | 383 | /* |
359 | * nfs4_file: a file opened by some number of (open) nfs4_stateowners. | 384 | * nfs4_file: a file opened by some number of (open) nfs4_stateowners. |
360 | * o fi_perfile list is used to search for conflicting | 385 | * o fi_perfile list is used to search for conflicting |
@@ -368,17 +393,17 @@ struct nfs4_file { | |||
368 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ | 393 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ |
369 | struct file * fi_fds[3]; | 394 | struct file * fi_fds[3]; |
370 | /* | 395 | /* |
371 | * Each open or lock stateid contributes 1 to either | 396 | * Each open or lock stateid contributes 0-4 to the counts |
372 | * fi_access[O_RDONLY], fi_access[O_WRONLY], or both, depending | 397 | * below depending on which bits are set in st_access_bitmap: |
373 | * on open or lock mode: | 398 | * 1 to fi_access[O_RDONLY] if NFS4_SHARE_ACCES_READ is set |
399 | * + 1 to fi_access[O_WRONLY] if NFS4_SHARE_ACCESS_WRITE is set | ||
400 | * + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set. | ||
374 | */ | 401 | */ |
375 | atomic_t fi_access[2]; | 402 | atomic_t fi_access[2]; |
376 | struct file *fi_deleg_file; | 403 | struct file *fi_deleg_file; |
377 | struct file_lock *fi_lease; | 404 | struct file_lock *fi_lease; |
378 | atomic_t fi_delegees; | 405 | atomic_t fi_delegees; |
379 | struct inode *fi_inode; | 406 | struct inode *fi_inode; |
380 | u32 fi_id; /* used with stateowner->so_id | ||
381 | * for stateid_hashtbl hash */ | ||
382 | bool fi_had_conflict; | 407 | bool fi_had_conflict; |
383 | }; | 408 | }; |
384 | 409 | ||
@@ -408,50 +433,27 @@ static inline struct file *find_any_file(struct nfs4_file *f) | |||
408 | return f->fi_fds[O_RDONLY]; | 433 | return f->fi_fds[O_RDONLY]; |
409 | } | 434 | } |
410 | 435 | ||
411 | /* | 436 | /* "ol" stands for "Open or Lock". Better suggestions welcome. */ |
412 | * nfs4_stateid can either be an open stateid or (eventually) a lock stateid | 437 | struct nfs4_ol_stateid { |
413 | * | 438 | struct nfs4_stid st_stid; /* must be first field */ |
414 | * (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file | ||
415 | * | ||
416 | * st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry | ||
417 | * st_perfile: file_hashtbl[] entry. | ||
418 | * st_perfile_state: nfs4_stateowner->so_perfilestate | ||
419 | * st_perlockowner: (open stateid) list of lock nfs4_stateowners | ||
420 | * st_access_bmap: used only for open stateid | ||
421 | * st_deny_bmap: used only for open stateid | ||
422 | * st_openstp: open stateid lock stateid was derived from | ||
423 | * | ||
424 | * XXX: open stateids and lock stateids have diverged sufficiently that | ||
425 | * we should consider defining separate structs for the two cases. | ||
426 | */ | ||
427 | |||
428 | struct nfs4_stateid { | ||
429 | struct list_head st_hash; | ||
430 | struct list_head st_perfile; | 439 | struct list_head st_perfile; |
431 | struct list_head st_perstateowner; | 440 | struct list_head st_perstateowner; |
432 | struct list_head st_lockowners; | 441 | struct list_head st_lockowners; |
433 | struct nfs4_stateowner * st_stateowner; | 442 | struct nfs4_stateowner * st_stateowner; |
434 | struct nfs4_file * st_file; | 443 | struct nfs4_file * st_file; |
435 | stateid_t st_stateid; | ||
436 | unsigned long st_access_bmap; | 444 | unsigned long st_access_bmap; |
437 | unsigned long st_deny_bmap; | 445 | unsigned long st_deny_bmap; |
438 | struct nfs4_stateid * st_openstp; | 446 | struct nfs4_ol_stateid * st_openstp; |
439 | }; | 447 | }; |
440 | 448 | ||
449 | static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) | ||
450 | { | ||
451 | return container_of(s, struct nfs4_ol_stateid, st_stid); | ||
452 | } | ||
453 | |||
441 | /* flags for preprocess_seqid_op() */ | 454 | /* flags for preprocess_seqid_op() */ |
442 | #define HAS_SESSION 0x00000001 | ||
443 | #define CONFIRM 0x00000002 | ||
444 | #define OPEN_STATE 0x00000004 | ||
445 | #define LOCK_STATE 0x00000008 | ||
446 | #define RD_STATE 0x00000010 | 455 | #define RD_STATE 0x00000010 |
447 | #define WR_STATE 0x00000020 | 456 | #define WR_STATE 0x00000020 |
448 | #define CLOSE_STATE 0x00000040 | ||
449 | |||
450 | #define seqid_mutating_err(err) \ | ||
451 | (((err) != nfserr_stale_clientid) && \ | ||
452 | ((err) != nfserr_bad_seqid) && \ | ||
453 | ((err) != nfserr_stale_stateid) && \ | ||
454 | ((err) != nfserr_bad_stateid)) | ||
455 | 457 | ||
456 | struct nfsd4_compound_state; | 458 | struct nfsd4_compound_state; |
457 | 459 | ||
@@ -461,7 +463,8 @@ extern void nfs4_lock_state(void); | |||
461 | extern void nfs4_unlock_state(void); | 463 | extern void nfs4_unlock_state(void); |
462 | extern int nfs4_in_grace(void); | 464 | extern int nfs4_in_grace(void); |
463 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); | 465 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); |
464 | extern void nfs4_free_stateowner(struct kref *kref); | 466 | extern void nfs4_free_openowner(struct nfs4_openowner *); |
467 | extern void nfs4_free_lockowner(struct nfs4_lockowner *); | ||
465 | extern int set_callback_cred(void); | 468 | extern int set_callback_cred(void); |
466 | extern void nfsd4_probe_callback(struct nfs4_client *clp); | 469 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
467 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | 470 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); |
@@ -473,7 +476,7 @@ extern void nfsd4_destroy_callback_queue(void); | |||
473 | extern void nfsd4_shutdown_callback(struct nfs4_client *); | 476 | extern void nfsd4_shutdown_callback(struct nfs4_client *); |
474 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); | 477 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); |
475 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); | 478 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); |
476 | extern void nfsd4_init_recdir(char *recdir_name); | 479 | extern void nfsd4_init_recdir(void); |
477 | extern int nfsd4_recdir_load(void); | 480 | extern int nfsd4_recdir_load(void); |
478 | extern void nfsd4_shutdown_recdir(void); | 481 | extern void nfsd4_shutdown_recdir(void); |
479 | extern int nfs4_client_to_reclaim(const char *name); | 482 | extern int nfs4_client_to_reclaim(const char *name); |
@@ -482,18 +485,7 @@ extern void nfsd4_recdir_purge_old(void); | |||
482 | extern int nfsd4_create_clid_dir(struct nfs4_client *clp); | 485 | extern int nfsd4_create_clid_dir(struct nfs4_client *clp); |
483 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); | 486 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); |
484 | extern void release_session_client(struct nfsd4_session *); | 487 | extern void release_session_client(struct nfsd4_session *); |
485 | extern __be32 nfs4_validate_stateid(stateid_t *, int); | 488 | extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); |
486 | 489 | extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); | |
487 | static inline void | ||
488 | nfs4_put_stateowner(struct nfs4_stateowner *so) | ||
489 | { | ||
490 | kref_put(&so->so_ref, nfs4_free_stateowner); | ||
491 | } | ||
492 | |||
493 | static inline void | ||
494 | nfs4_get_stateowner(struct nfs4_stateowner *so) | ||
495 | { | ||
496 | kref_get(&so->so_ref); | ||
497 | } | ||
498 | 490 | ||
499 | #endif /* NFSD4_STATE_H */ | 491 | #endif /* NFSD4_STATE_H */ |