1 /* NFSv4.1 client for Windows 2 * Copyright � 2012 The Regents of the University of Michigan 3 * 4 * Olga Kornievskaia <aglo@umich.edu> 5 * Casey Bodley <cbodley@umich.edu> 6 * 7 * This library is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as published by 9 * the Free Software Foundation; either version 2.1 of the License, or (at 10 * your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, but 13 * without any warranty; without even the implied warranty of merchantability 14 * or fitness for a particular purpose. See the GNU Lesser General Public 15 * License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 */ 21 22 #ifndef __NFS41__ 23 #define __NFS41__ 24 25 #include "util.h" 26 #include "list.h" 27 28 29 struct __nfs41_session; 30 struct __nfs41_client; 31 struct __rpc_client; 32 struct __nfs41_root; 33 34 struct _FILE_GET_EA_INFORMATION; 35 struct _FILE_FULL_EA_INFORMATION; 36 37 typedef struct __nfs41_superblock { 38 nfs41_fsid fsid; 39 struct list_entry entry; /* position in nfs41_server.superblocks */ 40 41 bitmap4 supported_attrs; 42 bitmap4 suppattr_exclcreat; 43 bitmap4 default_getattr; 44 45 nfstime4 time_delta; 46 uint64_t maxread; 47 uint64_t maxwrite; 48 49 /* constant filesystem attributes */ 50 unsigned int layout_types : 3; 51 unsigned int aclsupport : 3; 52 unsigned int cansettime : 1; 53 unsigned int link_support : 1; 54 unsigned int symlink_support : 1; 55 unsigned int ea_support : 1; 56 unsigned int case_preserving : 1; 57 unsigned int case_insensitive : 1; 58 59 /* variable filesystem attributes */ 60 uint64_t space_avail; 61 uint64_t space_free; 62 uint64_t space_total; 63 time_t cache_expiration; /* applies to space_ attributes */ 64 65 SRWLOCK lock; 66 } nfs41_superblock; 67 68 typedef struct __nfs41_superblock_list { 69 struct list_entry head; 70 SRWLOCK lock; 71 } nfs41_superblock_list; 72 73 struct server_addrs { 74 multi_addr4 addrs; /* list of addrs we've used with this server */ 75 uint32_t next_index; 76 SRWLOCK lock; 77 }; 78 79 typedef struct __nfs41_server { 80 char scope[NFS4_OPAQUE_LIMIT]; /* server_scope from exchangeid */ 81 char owner[NFS4_OPAQUE_LIMIT]; /* server_owner.major_id from exchangeid */ 82 struct server_addrs addrs; 83 nfs41_superblock_list superblocks; 84 struct nfs41_name_cache *name_cache; 85 struct list_entry entry; /* position in global server list */ 86 LONG ref_count; 87 } nfs41_server; 88 89 enum delegation_status { 90 DELEGATION_GRANTED, 91 DELEGATION_RETURNING, 92 DELEGATION_RETURNED, 93 }; 94 95 typedef struct __nfs41_delegation_state { 96 open_delegation4 state; 97 nfs41_abs_path path; 98 nfs41_path_fh parent; 99 nfs41_path_fh file; 100 struct list_entry client_entry; /* entry in nfs41_client.delegations */ 101 LONG ref_count; 102 103 enum delegation_status status; 104 SRWLOCK lock; 105 CONDITION_VARIABLE cond; 106 107 bool_t revoked; /* for recovery, accessed under client.state.lock */ 108 109 HANDLE srv_open; /* for rdbss cache invalidation */ 110 } nfs41_delegation_state; 111 112 typedef struct __nfs41_lock_state { 113 struct list_entry open_entry; /* entry in nfs41_open_state.locks */ 114 uint64_t offset; 115 uint64_t length; 116 uint32_t exclusive : 1; 117 uint32_t delegated : 1; /* whether or not there is state on the server */ 118 uint32_t id : 30; 119 } nfs41_lock_state; 120 121 /* nfs41_open_state reference counting: 122 * one reference is held implicitly by the driver (initialized to 1 on 123 * OPEN and released on CLOSE). other references must be held during 124 * upcalls to prevent a parallel CLOSE from freeing it prematurely. by 125 * calling upcall_open_state_ref() when parsing the upcall, you are 126 * guaranteed a matching dereference on upcall_cleanup() */ 127 typedef struct __nfs41_open_state { 128 nfs41_abs_path path; 129 nfs41_path_fh parent; 130 nfs41_path_fh file; 131 nfs41_readdir_cookie cookie; 132 struct __nfs41_session *session; 133 uint32_t type; 134 bool_t do_close; 135 stateid4 stateid; 136 state_owner4 owner; 137 struct __pnfs_layout_state *layout; 138 struct list_entry client_entry; /* entry in nfs41_client.opens */ 139 SRWLOCK lock; 140 LONG ref_count; 141 uint32_t share_access; 142 uint32_t share_deny; 143 uint64_t pnfs_last_offset; /* for layoutcommit */ 144 145 struct { 146 nfs41_delegation_state *state; 147 bool_t reclaim; 148 CONDITION_VARIABLE cond; 149 } delegation; 150 151 struct { /* list of open lock state for recovery */ 152 stateid4 stateid; 153 struct list_entry list; 154 uint32_t counter; 155 CRITICAL_SECTION lock; 156 } locks; 157 158 struct { 159 struct _FILE_GET_EA_INFORMATION *list; 160 uint32_t index; 161 CRITICAL_SECTION lock; 162 } ea; 163 164 HANDLE srv_open; /* for data cache invalidation */ 165 } nfs41_open_state; 166 167 typedef struct __nfs41_rpc_clnt { 168 struct __rpc_client *rpc; 169 SRWLOCK lock; 170 HANDLE cond; 171 struct __nfs41_client *client; 172 multi_addr4 addrs; 173 uint32_t addr_index; /* index of addr we're using */ 174 uint32_t wsize; 175 uint32_t rsize; 176 uint32_t version; 177 uint32_t sec_flavor; 178 uint32_t uid; 179 uint32_t gid; 180 char server_name[NI_MAXHOST]; 181 bool_t is_valid_session; 182 bool_t in_recovery; 183 bool_t needcb; 184 } nfs41_rpc_clnt; 185 186 struct client_state { 187 struct list_entry opens; /* list of associated nfs41_open_state */ 188 struct list_entry delegations; /* list of associated delegations */ 189 CRITICAL_SECTION lock; 190 }; 191 192 typedef struct __nfs41_client { 193 nfs41_server *server; 194 client_owner4 owner; 195 uint64_t clnt_id; 196 uint32_t seq_id; 197 uint32_t roles; 198 SRWLOCK exid_lock; 199 struct __nfs41_session *session; 200 SRWLOCK session_lock; 201 nfs41_rpc_clnt *rpc; 202 bool_t is_data; 203 struct pnfs_layout_list *layouts; 204 struct pnfs_file_device_list *devices; 205 struct list_entry root_entry; /* position in nfs41_root.clients */ 206 struct __nfs41_root *root; 207 208 struct { 209 CONDITION_VARIABLE cond; 210 CRITICAL_SECTION lock; 211 bool_t in_recovery; 212 } recovery; 213 214 /* for state recovery on server reboot */ 215 struct client_state state; 216 } nfs41_client; 217 218 #define NFS41_MAX_NUM_SLOTS NFS41_MAX_RPC_REQS 219 typedef struct __nfs41_slot_table { 220 uint32_t seq_nums[NFS41_MAX_NUM_SLOTS]; 221 uint32_t used_slots[NFS41_MAX_NUM_SLOTS]; 222 uint32_t max_slots; 223 uint32_t highest_used; 224 uint32_t num_used; 225 ULONGLONG target_delay; 226 CRITICAL_SECTION lock; 227 CONDITION_VARIABLE cond; 228 } nfs41_slot_table; 229 230 typedef struct __nfs41_channel_attrs { 231 uint32_t ca_headerpadsize; 232 uint32_t ca_maxrequestsize; 233 uint32_t ca_maxresponsesize; 234 uint32_t ca_maxresponsesize_cached; 235 uint32_t ca_maxoperations; 236 uint32_t ca_maxrequests; 237 uint32_t *ca_rdma_ird; 238 } nfs41_channel_attrs; 239 240 struct replay_cache { 241 unsigned char buffer[NFS41_MAX_SERVER_CACHE]; 242 uint32_t length; 243 }; 244 245 typedef struct __nfs41_cb_session { 246 struct { 247 struct replay_cache arg; 248 struct replay_cache res; 249 } replay; 250 const unsigned char *cb_sessionid; /* -> nfs41_session.session_id */ 251 uint32_t cb_seqnum; 252 uint32_t cb_slotid; 253 } nfs41_cb_session; 254 255 typedef struct __nfs41_session { 256 nfs41_client *client; 257 unsigned char session_id[NFS4_SESSIONID_SIZE]; 258 nfs41_channel_attrs fore_chan_attrs; 259 nfs41_channel_attrs back_chan_attrs; 260 uint32_t lease_time; 261 nfs41_slot_table table; 262 // array of slots 263 HANDLE renew_thread; 264 bool_t isValidState; 265 uint32_t flags; 266 nfs41_cb_session cb_session; 267 } nfs41_session; 268 269 /* nfs41_root reference counting: 270 * similar to nfs41_open_state, the driver holds an implicit reference 271 * between MOUNT and UNMOUNT. all other upcalls use upcall_root_ref() on 272 * upcall_parse(), which prevents the root/clients from being freed and 273 * guarantees a matching deref on upcall_cleanup() */ 274 typedef struct __nfs41_root { 275 client_owner4 client_owner; 276 CRITICAL_SECTION lock; 277 struct list_entry clients; 278 uint32_t wsize; 279 uint32_t rsize; 280 LONG ref_count; 281 uint32_t uid; 282 uint32_t gid; 283 DWORD sec_flavor; 284 } nfs41_root; 285 286 287 /* nfs41_namespace.c */ 288 int nfs41_root_create( 289 IN const char *name, 290 IN uint32_t sec_flavor, 291 IN uint32_t wsize, 292 IN uint32_t rsize, 293 OUT nfs41_root **root_out); 294 295 void nfs41_root_ref( 296 IN nfs41_root *root); 297 298 void nfs41_root_deref( 299 IN nfs41_root *root); 300 301 int nfs41_root_mount_addrs( 302 IN nfs41_root *root, 303 IN const multi_addr4 *addrs, 304 IN bool_t is_data, 305 IN OPTIONAL uint32_t lease_time, 306 OUT nfs41_client **client_out); 307 308 int nfs41_root_mount_server( 309 IN nfs41_root *root, 310 IN nfs41_server *server, 311 IN bool_t is_data, 312 IN OPTIONAL uint32_t lease_time, 313 OUT nfs41_client **client_out); 314 315 int nfs41_root_mount_referral( 316 IN nfs41_root *root, 317 IN const fs_locations4 *locations, 318 OUT const fs_location4 **loc_out, 319 OUT nfs41_client **client_out); 320 321 static __inline nfs41_session* nfs41_root_session( 322 IN nfs41_root *root) 323 { 324 nfs41_client *client; 325 /* return a session for the server at the root of the namespace. 326 * because we created it on mount, it's the first one in the list */ 327 EnterCriticalSection(&root->lock); 328 client = list_container(root->clients.next, nfs41_client, root_entry); 329 LeaveCriticalSection(&root->lock); 330 return client->session; 331 } 332 333 334 /* nfs41_session.c */ 335 int nfs41_session_create( 336 IN nfs41_client *client, 337 IN nfs41_session **session_out); 338 339 int nfs41_session_renew( 340 IN nfs41_session *session); 341 342 int nfs41_session_set_lease( 343 IN nfs41_session *session, 344 IN uint32_t lease_time); 345 346 void nfs41_session_free( 347 IN nfs41_session *session); 348 349 void nfs41_session_bump_seq( 350 IN nfs41_session *session, 351 IN uint32_t slotid, 352 IN uint32_t target_highest_slotid); 353 354 void nfs41_session_free_slot( 355 IN nfs41_session *session, 356 IN uint32_t slotid); 357 358 void nfs41_session_get_slot( 359 IN nfs41_session *session, 360 OUT uint32_t *slot, 361 OUT uint32_t *seq, 362 OUT uint32_t *highest); 363 364 int nfs41_session_recall_slot( 365 IN nfs41_session *session, 366 IN OUT uint32_t target_highest_slotid); 367 368 struct __nfs41_sequence_args; 369 void nfs41_session_sequence( 370 struct __nfs41_sequence_args *args, 371 nfs41_session *session, 372 bool_t cachethis); 373 374 int nfs41_session_bad_slot( 375 IN nfs41_session *session, 376 IN OUT struct __nfs41_sequence_args *args); 377 378 379 /* nfs41_server.c */ 380 void nfs41_server_list_init(); 381 382 int nfs41_server_resolve( 383 IN const char *hostname, 384 IN unsigned short port, 385 OUT multi_addr4 *addrs); 386 387 int nfs41_server_find_or_create( 388 IN const char *server_owner_major_id, 389 IN const char *server_scope, 390 IN const netaddr4 *addr, 391 OUT nfs41_server **server_out); 392 393 void nfs41_server_ref( 394 IN nfs41_server *server); 395 396 void nfs41_server_deref( 397 IN nfs41_server *server); 398 399 void nfs41_server_addrs( 400 IN nfs41_server *server, 401 OUT multi_addr4 *addrs); 402 403 404 /* nfs41_client.c */ 405 int nfs41_client_owner( 406 IN const char *name, 407 IN uint32_t sec_flavor, 408 OUT client_owner4 *owner); 409 410 uint32_t nfs41_exchange_id_flags( 411 IN bool_t is_data); 412 413 struct __nfs41_exchange_id_res; 414 415 int nfs41_client_create( 416 IN nfs41_rpc_clnt *rpc, 417 IN const client_owner4 *owner, 418 IN bool_t is_data, 419 IN const struct __nfs41_exchange_id_res *exchangeid, 420 OUT nfs41_client **client_out); 421 422 int nfs41_client_renew( 423 IN nfs41_client *client); 424 425 void nfs41_client_free( 426 IN nfs41_client *client); 427 428 static __inline nfs41_server* client_server( 429 IN nfs41_client *client) 430 { 431 /* the client's server could change during nfs41_client_renew(), 432 * so access to client->server must be protected */ 433 nfs41_server *server; 434 AcquireSRWLockShared(&client->exid_lock); 435 server = client->server; 436 ReleaseSRWLockShared(&client->exid_lock); 437 return server; 438 } 439 440 441 /* nfs41_superblock.c */ 442 int nfs41_superblock_for_fh( 443 IN nfs41_session *session, 444 IN const nfs41_fsid *fsid, 445 IN const nfs41_fh *parent OPTIONAL, 446 OUT nfs41_path_fh *file); 447 448 static __inline void nfs41_superblock_getattr_mask( 449 IN const nfs41_superblock *superblock, 450 OUT bitmap4 *attrs) 451 { 452 memcpy(attrs, &superblock->default_getattr, sizeof(bitmap4)); 453 } 454 static __inline void nfs41_superblock_supported_attrs( 455 IN const nfs41_superblock *superblock, 456 IN OUT bitmap4 *attrs) 457 { 458 bitmap_intersect(attrs, &superblock->supported_attrs); 459 } 460 static __inline void nfs41_superblock_supported_attrs_exclcreat( 461 IN const nfs41_superblock *superblock, 462 IN OUT bitmap4 *attrs) 463 { 464 bitmap_intersect(attrs, &superblock->suppattr_exclcreat); 465 } 466 467 struct _FILE_FS_ATTRIBUTE_INFORMATION; 468 void nfs41_superblock_fs_attributes( 469 IN const nfs41_superblock *superblock, 470 OUT struct _FILE_FS_ATTRIBUTE_INFORMATION *FsAttrs); 471 472 void nfs41_superblock_space_changed( 473 IN nfs41_superblock *superblock); 474 475 void nfs41_superblock_list_init( 476 IN nfs41_superblock_list *superblocks); 477 478 void nfs41_superblock_list_free( 479 IN nfs41_superblock_list *superblocks); 480 481 482 /* nfs41_rpc.c */ 483 int nfs41_rpc_clnt_create( 484 IN const multi_addr4 *addrs, 485 IN uint32_t wsize, 486 IN uint32_t rsize, 487 IN uint32_t uid, 488 IN uint32_t gid, 489 IN uint32_t sec_flavor, 490 OUT nfs41_rpc_clnt **rpc_out); 491 492 void nfs41_rpc_clnt_free( 493 IN nfs41_rpc_clnt *rpc); 494 495 int nfs41_send_compound( 496 IN nfs41_rpc_clnt *rpc, 497 IN char *inbuf, 498 OUT char *outbuf); 499 500 static __inline netaddr4* nfs41_rpc_netaddr( 501 IN nfs41_rpc_clnt *rpc) 502 { 503 uint32_t id; 504 AcquireSRWLockShared(&rpc->lock); 505 /* only addr_index needs to be protected, as rpc->addrs is write-once */ 506 id = rpc->addr_index; 507 ReleaseSRWLockShared(&rpc->lock); 508 509 /* return the netaddr used to create the rpc client */ 510 return &rpc->addrs.arr[id]; 511 } 512 513 514 /* open.c */ 515 void nfs41_open_state_ref( 516 IN nfs41_open_state *state); 517 518 void nfs41_open_state_deref( 519 IN nfs41_open_state *state); 520 521 struct __stateid_arg; 522 void nfs41_open_stateid_arg( 523 IN nfs41_open_state *state, 524 OUT struct __stateid_arg *arg); 525 526 527 /* ea.c */ 528 int nfs41_ea_set( 529 IN nfs41_open_state *state, 530 IN struct _FILE_FULL_EA_INFORMATION *ea); 531 532 #endif /* __NFS41__ */ 533