ReactOS  0.4.13-dev-455-g28ed234
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)
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 {
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 */
126  AcquireSRWLockShared(&client->exid_lock);
127  roles = info->roles & client->roles;
128  ReleaseSRWLockShared(&client->exid_lock);
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 {
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 {
181  const struct cl_exid_info *info = (const struct cl_exid_info*)value;
183 
184  AcquireSRWLockShared(&client->exid_lock);
185 
186  /* match any of the desired roles */
187  if ((info->roles & client->roles) == 0)
188  goto out;
189  /* match server_owner.major_id */
190  if (strncmp(info->exchangeid->server_owner.so_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:
203  ReleaseSRWLockShared(&client->exid_lock);
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 {
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",
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",
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:
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));
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 */
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 {
442  multi_addr4 addrs;
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++) {
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 }
#define IN
Definition: typedefs.h:38
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
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
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
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
unsigned int count
Definition: notification.c:64
__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
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static void root_free(IN nfs41_root *root)
Definition: namespace.c:76
long LONG
Definition: pedump.c:60
#define dprintf
Definition: regdump.c:33
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
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
const multi_addr4 * addrs
Definition: namespace.c:113
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
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
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
#define InterlockedDecrement
Definition: armddk.h:52
uint32_t entry
Definition: isohybrid.c:63
GLsizei const GLint * locations
Definition: glext.h:10542
int nfs41_session_create(IN nfs41_client *client, IN nfs41_session **session_out)
int nfs41_client_owner(IN const char *name, IN uint32_t sec_flavor, OUT client_owner4 *owner)
Definition: nfs41_client.c:358
uint32_t roles
Definition: namespace.c:173
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
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
sec_flavor
Definition: nfs41_ops.h:861
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
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
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
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