ReactOS  0.4.12-dev-75-g00dd17e
namespace.c
Go to the documentation of this file.
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 #include <windows.h>
23 #include <strsafe.h>
24 
25 #include "nfs41_ops.h"
26 #include "util.h"
27 #include "daemon_debug.h"
28 
29 
30 #define NSLVL 2 /* dprintf level for namespace logging */
31 
32 
33 #define client_entry(pos) list_container(pos, nfs41_client, root_entry)
34 
35 
36 /* nfs41_root */
38  IN const char *name,
40  IN uint32_t wsize,
41  IN uint32_t rsize,
42  OUT nfs41_root **root_out)
43 {
44  int status = NO_ERROR;
46 
47  dprintf(NSLVL, "--> nfs41_root_create()\n");
48 
49  root = calloc(1, sizeof(nfs41_root));
50  if (root == NULL) {
51  status = GetLastError();
52  goto out;
53  }
54 
55  list_init(&root->clients);
56  root->wsize = wsize;
57  root->rsize = rsize;
59  root->ref_count = 1;
60  root->sec_flavor = sec_flavor;
61 
62  /* generate a unique client_owner */
63  status = nfs41_client_owner(name, sec_flavor, &root->client_owner);
64  if (status) {
65  eprintf("nfs41_client_owner() failed with %d\n", status);
66  free(root);
67  goto out;
68  }
69 
70  *root_out = root;
71 out:
72  dprintf(NSLVL, "<-- nfs41_root_create() returning %d\n", status);
73  return status;
74 }
75 
76 static void root_free(
78 {
79  struct list_entry *entry, *tmp;
80 
81  dprintf(NSLVL, "--> nfs41_root_free()\n");
82 
83  /* free clients */
84  list_for_each_tmp(entry, tmp, &root->clients)
86  DeleteCriticalSection(&root->lock);
87  free(root);
88 
89  dprintf(NSLVL, "<-- nfs41_root_free()\n");
90 }
91 
94 {
95  const LONG count = InterlockedIncrement(&root->ref_count);
96 
97  dprintf(NSLVL, "nfs41_root_ref() count %d\n", count);
98 }
99 
101  IN nfs41_root *root)
102 {
103  const LONG count = InterlockedDecrement(&root->ref_count);
104 
105  dprintf(NSLVL, "nfs41_root_deref() count %d\n", count);
106  if (count == 0)
107  root_free(root);
108 }
109 
110 
111 /* root_client_find_addrs() */
112 struct cl_addr_info {
115 };
116 
117 static int cl_addr_compare(
118  IN const struct list_entry *entry,
119  IN const void *value)
120 {
121  nfs41_client *client = client_entry(entry);
122  const struct cl_addr_info *info = (const struct cl_addr_info*)value;
123  uint32_t i, roles;
124 
125  /* match any of the desired roles */
127  roles = info->roles & client->roles;
129 
130  if (roles == 0)
131  return ERROR_FILE_NOT_FOUND;
132 
133  /* match any address in 'addrs' with any address in client->rpc->addrs */
134  for (i = 0; i < info->addrs->count; i++)
135  if (multi_addr_find(&client->rpc->addrs, &info->addrs->arr[i], NULL))
136  return NO_ERROR;
137 
138  return ERROR_FILE_NOT_FOUND;
139 }
140 
142  IN nfs41_root *root,
143  IN const multi_addr4 *addrs,
144  IN bool_t is_data,
145  OUT nfs41_client **client_out)
146 {
147  struct cl_addr_info info;
148  struct list_entry *entry;
149  int status;
150 
151  dprintf(NSLVL, "--> root_client_find_addrs()\n");
152 
153  info.addrs = addrs;
155 
156  entry = list_search(&root->clients, &info, cl_addr_compare);
157  if (entry) {
158  *client_out = client_entry(entry);
159  status = NO_ERROR;
160  dprintf(NSLVL, "<-- root_client_find_addrs() returning 0x%p\n",
161  *client_out);
162  } else {
163  status = ERROR_FILE_NOT_FOUND;
164  dprintf(NSLVL, "<-- root_client_find_addrs() failed with %d\n",
165  status);
166  }
167  return status;
168 }
169 
170 /* root_client_find() */
171 struct cl_exid_info {
174 };
175 
176 static int cl_exid_compare(
177  IN const struct list_entry *entry,
178  IN const void *value)
179 {
180  nfs41_client *client = client_entry(entry);
181  const struct cl_exid_info *info = (const struct cl_exid_info*)value;
183 
185 
186  /* match any of the desired roles */
187  if ((info->roles & client->roles) == 0)
188  goto out;
189  /* match server_owner.major_id */
191  client->server->owner, NFS4_OPAQUE_LIMIT) != 0)
192  goto out;
193  /* match server_scope */
194  if (strncmp(info->exchangeid->server_scope,
195  client->server->scope, NFS4_OPAQUE_LIMIT) != 0)
196  goto out;
197  /* match clientid */
198  if (info->exchangeid->clientid != client->clnt_id)
199  goto out;
200 
201  status = NO_ERROR;
202 out:
204  return status;
205 }
206 
207 static int root_client_find(
208  IN nfs41_root *root,
210  IN bool_t is_data,
211  OUT nfs41_client **client_out)
212 {
213  struct cl_exid_info info;
214  struct list_entry *entry;
215  int status;
216 
217  dprintf(NSLVL, "--> root_client_find()\n");
218 
219  info.exchangeid = exchangeid;
221 
222  entry = list_search(&root->clients, &info, cl_exid_compare);
223  if (entry) {
224  *client_out = client_entry(entry);
225  status = NO_ERROR;
226  dprintf(NSLVL, "<-- root_client_find() returning 0x%p\n",
227  *client_out);
228  } else {
229  status = ERROR_FILE_NOT_FOUND;
230  dprintf(NSLVL, "<-- root_client_find() failed with %d\n",
231  status);
232  }
233  return status;
234 }
235 
236 static int session_get_lease(
237  IN nfs41_session *session,
238  IN OPTIONAL uint32_t lease_time)
239 {
240  bool_t use_mds_lease;
241  int status;
242 
243  /* http://tools.ietf.org/html/rfc5661#section-13.1.1
244  * 13.1.1. Sessions Considerations for Data Servers:
245  * If the reply to EXCHANGE_ID has just the EXCHGID4_FLAG_USE_PNFS_DS role
246  * set, then (as noted in Section 13.6) the client will not be able to
247  * determine the data server's lease_time attribute because GETATTR will
248  * not be permitted. Instead, the rule is that any time a client
249  * receives a layout referring it to a data server that returns just the
250  * EXCHGID4_FLAG_USE_PNFS_DS role, the client MAY assume that the
251  * lease_time attribute from the metadata server that returned the
252  * layout applies to the data server. */
253  AcquireSRWLockShared(&session->client->exid_lock);
254  use_mds_lease = session->client->roles == EXCHGID4_FLAG_USE_PNFS_DS;
255  ReleaseSRWLockShared(&session->client->exid_lock);
256 
257  if (!use_mds_lease) {
258  /* the client is allowed to GETATTR, so query the lease_time */
259  nfs41_file_info info = { 0 };
260  bitmap4 attr_request = { 1, { FATTR4_WORD0_LEASE_TIME, 0, 0 } };
261 
262  status = nfs41_getattr(session, NULL, &attr_request, &info);
263  if (status) {
264  eprintf("nfs41_getattr() failed with %s\n",
265  nfs_error_string(status));
266  status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
267  goto out;
268  }
269  lease_time = info.lease_time;
270  }
271 
272  status = nfs41_session_set_lease(session, lease_time);
273  if (status) {
274  eprintf("nfs41_session_set_lease() failed %d\n", status);
275  goto out;
276  }
277 out:
278  return status;
279 }
280 
282  IN nfs41_root *root,
283  IN nfs41_rpc_clnt *rpc,
284  IN bool_t is_data,
285  IN OPTIONAL uint32_t lease_time,
286  IN const nfs41_exchange_id_res *exchangeid,
287  OUT nfs41_client **client_out)
288 {
290  nfs41_session *session;
291  int status;
292 
293  /* create client (transfers ownership of rpc to client) */
294  status = nfs41_client_create(rpc, &root->client_owner,
295  is_data, exchangeid, &client);
296  if (status) {
297  eprintf("nfs41_client_create() failed with %d\n", status);
298  goto out;
299  }
300  client->root = root;
301  rpc->client = client;
302 
303  /* create session (and client takes ownership) */
304  status = nfs41_session_create(client, &session);
305  if (status) {
306  eprintf("nfs41_session_create failed %d\n", status);
307  goto out_err;
308  }
309 
310  if (!is_data) {
311  /* send RECLAIM_COMPLETE, but don't fail on ERR_NOTSUPP */
312  status = nfs41_reclaim_complete(session);
313  if (status && status != NFS4ERR_NOTSUPP) {
314  eprintf("nfs41_reclaim_complete() failed with %s\n",
315  nfs_error_string(status));
316  status = ERROR_BAD_NETPATH;
317  goto out_err;
318  }
319  }
320 
321  /* get least time and start session renewal thread */
322  status = session_get_lease(session, lease_time);
323  if (status)
324  goto out_err;
325 
326  *client_out = client;
327 out:
328  return status;
329 
330 out_err:
331  nfs41_client_free(client);
332  goto out;
333 }
334 
336  IN nfs41_root *root,
337  IN const multi_addr4 *addrs,
338  IN bool_t is_data,
339  IN OPTIONAL uint32_t lease_time,
340  OUT nfs41_client **client_out)
341 {
342  nfs41_exchange_id_res exchangeid = { 0 };
343  nfs41_rpc_clnt *rpc;
344  nfs41_client *client, *existing;
345  int status;
346 
347  dprintf(NSLVL, "--> nfs41_root_mount_addrs()\n");
348 
349  /* look for an existing client that matches the address and role */
350  EnterCriticalSection(&root->lock);
351  status = root_client_find_addrs(root, addrs, is_data, &client);
352  LeaveCriticalSection(&root->lock);
353 
354  if (status == NO_ERROR)
355  goto out;
356 
357  /* create an rpc client */
358  status = nfs41_rpc_clnt_create(addrs, root->wsize, root->rsize,
359  root->uid, root->gid, root->sec_flavor, &rpc);
360  if (status) {
361  eprintf("nfs41_rpc_clnt_create() failed %d\n", status);
362  goto out;
363  }
364 
365  /* get a clientid with exchangeid */
366  status = nfs41_exchange_id(rpc, &root->client_owner,
367  nfs41_exchange_id_flags(is_data), &exchangeid);
368  if (status) {
369  eprintf("nfs41_exchange_id() failed %s\n", nfs_error_string(status));
370  status = ERROR_BAD_NET_RESP;
371  goto out_free_rpc;
372  }
373 
374  /* attempt to match existing clients by the exchangeid response */
375  EnterCriticalSection(&root->lock);
376  status = root_client_find(root, &exchangeid, is_data, &client);
377  LeaveCriticalSection(&root->lock);
378 
379  if (status == NO_ERROR)
380  goto out_free_rpc;
381 
382  /* create a client for this clientid */
383  status = root_client_create(root, rpc, is_data,
384  lease_time, &exchangeid, &client);
385  if (status) {
386  eprintf("nfs41_client_create() failed %d\n", status);
387  /* root_client_create takes care of cleaning up
388  * thus don't go to out_free_rpc */
389  goto out;
390  }
391 
392  /* because we don't hold the root's lock over session creation,
393  * we could end up creating multiple clients with the same
394  * server and roles */
395  EnterCriticalSection(&root->lock);
396  status = root_client_find(root, &exchangeid, is_data, &existing);
397 
398  if (status) {
399  dprintf(NSLVL, "caching new client 0x%p\n", client);
400 
401  /* the client is not a duplicate, so add it to the list */
402  list_add_tail(&root->clients, &client->root_entry);
403  status = NO_ERROR;
404  } else {
405  dprintf(NSLVL, "created a duplicate client 0x%p! using "
406  "existing client 0x%p instead\n", client, existing);
407 
408  /* a matching client has been created in parallel, so free
409  * the one we created and use the existing client instead */
410  nfs41_client_free(client);
411  client = existing;
412  }
413  LeaveCriticalSection(&root->lock);
414 
415 out:
416  if (status == NO_ERROR)
417  *client_out = client;
418  dprintf(NSLVL, "<-- nfs41_root_mount_addrs() returning %d\n", status);
419  return status;
420 
421 out_free_rpc:
422  nfs41_rpc_clnt_free(rpc);
423  goto out;
424 }
425 
426 
427 /* http://tools.ietf.org/html/rfc5661#section-11.9
428  * 11.9. The Attribute fs_locations
429  * An entry in the server array is a UTF-8 string and represents one of a
430  * traditional DNS host name, IPv4 address, IPv6 address, or a zero-length
431  * string. An IPv4 or IPv6 address is represented as a universal address
432  * (see Section 3.3.9 and [15]), minus the netid, and either with or without
433  * the trailing ".p1.p2" suffix that represents the port number. If the
434  * suffix is omitted, then the default port, 2049, SHOULD be assumed. A
435  * zero-length string SHOULD be used to indicate the current address being
436  * used for the RPC call. */
438  IN nfs41_root *root,
439  IN const fs_location4 *loc,
440  OUT nfs41_client **client_out)
441 {
444  uint32_t i;
445 
446  /* create a client and session for the first available server */
447  for (i = 0; i < loc->server_count; i++) {
448  /* XXX: only deals with 'address' as a hostname with default port */
449  status = nfs41_server_resolve(loc->servers[i].address, 2049, &addrs);
450  if (status) continue;
451 
452  status = nfs41_root_mount_addrs(root, &addrs, 0, 0, client_out);
453  if (status == NO_ERROR)
454  break;
455  }
456  return status;
457 }
458 
460  IN nfs41_root *root,
461  IN const fs_locations4 *locations,
462  OUT const fs_location4 **loc_out,
463  OUT nfs41_client **client_out)
464 {
466  uint32_t i;
467 
468  /* establish a mount to the first available location */
469  for (i = 0; i < locations->location_count; i++) {
470  status = referral_mount_location(root,
471  &locations->locations[i], client_out);
472  if (status == NO_ERROR) {
473  *loc_out = &locations->locations[i];
474  break;
475  }
476  }
477  return status;
478 }
char owner[NFS4_OPAQUE_LIMIT]
Definition: nfs41.h:81
#define IN
Definition: typedefs.h:38
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
Definition: get.c:139
SRWLOCK exid_lock
Definition: nfs41.h:198
void nfs41_client_free(IN nfs41_client *client)
Definition: nfs41_client.c:206
int nfs41_rpc_clnt_create(IN const multi_addr4 *addrs, IN uint32_t wsize, IN uint32_t rsize, IN uint32_t uid, IN uint32_t gid, IN uint32_t sec_flavor, OUT nfs41_rpc_clnt **rpc_out)
Definition: nfs41_rpc.c:145
int32_t bool_t
Definition: types.h:101
uint32_t wsize
Definition: nfs41.h:278
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define ERROR_BAD_NET_NAME
Definition: winerror.h:159
#define free
Definition: debug_ros.c:5
struct _root root
uint8_t entry
Definition: isohybrid.c:63
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
int nfs41_session_set_lease(IN nfs41_session *session, IN uint32_t lease_time)
void nfs41_rpc_clnt_free(IN nfs41_rpc_clnt *rpc)
Definition: nfs41_rpc.c:243
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
static int cl_addr_compare(IN const struct list_entry *entry, IN const void *value)
Definition: namespace.c:117
#define NO_ERROR
Definition: dderror.h:5
#define ERROR_BAD_NETPATH
Definition: winerror.h:145
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
#define ERROR_BAD_NET_RESP
Definition: winerror.h:150
GLenum GLclampf GLint i
Definition: glfuncs.h:14
static void root_free(IN nfs41_root *root)
Definition: namespace.c:76
long LONG
Definition: pedump.c:60
client_owner4 client_owner
Definition: nfs41.h:275
#define dprintf
Definition: regdump.c:33
uint32_t roles
Definition: nfs41.h:197
int nfs41_root_mount_addrs(IN nfs41_root *root, IN const multi_addr4 *addrs, IN bool_t is_data, IN OPTIONAL uint32_t lease_time, OUT nfs41_client **client_out)
Definition: namespace.c:335
#define NFS4_OPAQUE_LIMIT
Definition: nfs41_const.h:31
nfs41_rpc_clnt * rpc
Definition: nfs41.h:201
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:697
smooth NULL
Definition: ftsmooth.c:416
static int root_client_create(IN nfs41_root *root, IN nfs41_rpc_clnt *rpc, IN bool_t is_data, IN OPTIONAL uint32_t lease_time, IN const nfs41_exchange_id_res *exchangeid, OUT nfs41_client **client_out)
Definition: namespace.c:281
#define client_entry(pos)
Definition: namespace.c:33
int nfs41_getattr(IN nfs41_session *session, IN OPTIONAL nfs41_path_fh *file, IN bitmap4 *attr_request, OUT nfs41_file_info *info)
Definition: nfs41_ops.c:1063
void nfs41_root_ref(IN nfs41_root *root)
Definition: namespace.c:92
static int cl_exid_compare(IN const struct list_entry *entry, IN const void *value)
Definition: namespace.c:176
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
int nfs41_server_resolve(IN const char *hostname, IN unsigned short port, OUT multi_addr4 *addrs)
Definition: nfs41_server.c:275
uint32_t nfs41_exchange_id_flags(IN bool_t is_data)
Definition: nfs41_client.c:36
static int referral_mount_location(IN nfs41_root *root, IN const fs_location4 *loc, OUT nfs41_client **client_out)
Definition: namespace.c:437
server_owner4 server_owner
Definition: nfs41_ops.h:137
const multi_addr4 * addrs
Definition: namespace.c:113
char so_major_id[NFS4_OPAQUE_LIMIT]
Definition: nfs41_types.h:114
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
multi_addr4 addrs
Definition: nfs41.h:172
struct list_entry root_entry
Definition: nfs41.h:205
static int root_client_find(IN nfs41_root *root, IN const nfs41_exchange_id_res *exchangeid, IN bool_t is_data, OUT nfs41_client **client_out)
Definition: namespace.c:207
nfs41_server * server
Definition: nfs41.h:193
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static FILE * client
Definition: client.c:41
static FILE * out
Definition: regtests2xml.c:44
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
const nfs41_exchange_id_res * exchangeid
Definition: namespace.c:172
int nfs41_exchange_id(IN nfs41_rpc_clnt *rpc, IN client_owner4 *owner, IN uint32_t flags_in, OUT nfs41_exchange_id_res *res_out)
Definition: nfs41_ops.c:36
struct __nfs41_root * root
Definition: nfs41.h:206
#define InterlockedDecrement
Definition: armddk.h:52
GLsizei const GLint * locations
Definition: glext.h:10542
int nfs41_session_create(IN nfs41_client *client, IN nfs41_session **session_out)
uint32_t count
Definition: nfs41_types.h:92
int nfs41_client_owner(IN const char *name, IN uint32_t sec_flavor, OUT client_owner4 *owner)
Definition: nfs41_client.c:358
char scope[NFS4_OPAQUE_LIMIT]
Definition: nfs41.h:80
uint32_t roles
Definition: namespace.c:173
uint64_t clnt_id
Definition: nfs41.h:195
static struct list_entry * list_search(const struct list_entry *head, const void *value, list_compare_fn compare)
Definition: list.h:102
#define InterlockedIncrement
Definition: armddk.h:53
static int root_client_find_addrs(IN nfs41_root *root, IN const multi_addr4 *addrs, IN bool_t is_data, OUT nfs41_client **client_out)
Definition: namespace.c:141
char server_scope[NFS4_OPAQUE_LIMIT]
Definition: nfs41_ops.h:139
int nfs41_root_create(IN const char *name, IN uint32_t sec_flavor, IN uint32_t wsize, IN uint32_t rsize, OUT nfs41_root **root_out)
Definition: namespace.c:37
Definition: list.h:27
UINT32 uint32_t
Definition: types.h:75
int nfs41_client_create(IN nfs41_rpc_clnt *rpc, IN const client_owner4 *owner, IN bool_t is_data, IN const struct __nfs41_exchange_id_res *exchangeid, OUT nfs41_client **client_out)
Definition: name.c:36
#define list_for_each_tmp(entry, tmp, head)
Definition: list.h:39
#define calloc
Definition: rosglue.h:14
#define OUT
Definition: typedefs.h:39
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
uint32_t roles
Definition: namespace.c:114
static int session_get_lease(IN nfs41_session *session, IN OPTIONAL uint32_t lease_time)
Definition: namespace.c:236
void nfs41_root_deref(IN nfs41_root *root)
Definition: namespace.c:100
netaddr4 arr[NFS41_ADDRS_PER_SERVER]
Definition: nfs41_types.h:91
DWORD sec_flavor
Definition: nfs41.h:283
sec_flavor
Definition: nfs41_ops.h:861
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
LONG ref_count
Definition: nfs41.h:280
struct list_entry clients
Definition: nfs41.h:277
CRITICAL_SECTION lock
Definition: nfs41.h:276
static SERVICE_STATUS status
Definition: service.c:31
int nfs41_root_mount_referral(IN nfs41_root *root, IN const fs_locations4 *locations, OUT const fs_location4 **loc_out, OUT nfs41_client **client_out)
Definition: namespace.c:459
uint32_t rsize
Definition: nfs41.h:279
bool_t multi_addr_find(IN const multi_addr4 *addrs, IN const netaddr4 *addr, OUT OPTIONAL uint32_t *index_out)
Definition: util.c:218
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
uint32_t lease_time
Definition: nfs41_types.h:233
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
#define NSLVL
Definition: namespace.c:30
enum nfsstat4 nfs41_reclaim_complete(IN nfs41_session *session)
Definition: nfs41_ops.c:268
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68