ReactOS 0.4.15-dev-7788-g1ad9096
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) {
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;
71out:
72 dprintf(NSLVL, "<-- nfs41_root_create() returning %d\n", status);
73 return status;
74}
75
76static 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
102{
103 const LONG count = InterlockedDecrement(&root->ref_count);
104
105 dprintf(NSLVL, "nfs41_root_deref() count %d\n", count);
106 if (count == 0)
108}
109
110
111/* root_client_find_addrs() */
115};
116
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;
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)
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
139}
140
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);
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() */
174};
175
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
202out:
203 ReleaseSRWLockShared(&client->exid_lock);
204 return status;
205}
206
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);
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
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
273 if (status) {
274 eprintf("nfs41_session_set_lease() failed %d\n", status);
275 goto out;
276 }
277out:
278 return status;
279}
280
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{
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) */
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 */
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;
327out:
328 return status;
329
330out_err:
332 goto out;
333}
334
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 */
351 status = root_client_find_addrs(root, addrs, is_data, &client);
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 */
376 status = root_client_find(root, &exchangeid, is_data, &client);
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 */
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);
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 }
414
415out:
416 if (status == NO_ERROR)
417 *client_out = client;
418 dprintf(NSLVL, "<-- nfs41_root_mount_addrs() returning %d\n", status);
419 return status;
420
421out_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. */
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
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}
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define list_for_each_tmp(entry, tmp, head)
Definition: list.h:39
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static struct list_entry * list_search(const struct list_entry *head, const void *value, list_compare_fn compare)
Definition: list.h:102
static void list_init(struct list_entry *head)
Definition: list.h:51
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
bool_t multi_addr_find(IN const multi_addr4 *addrs, IN const netaddr4 *addr, OUT OPTIONAL uint32_t *index_out)
Definition: util.c:218
struct _root root
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
#define NO_ERROR
Definition: dderror.h:5
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
int32_t bool_t
Definition: types.h:101
UINT32 uint32_t
Definition: types.h:75
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLsizei const GLint * locations
Definition: glext.h:10542
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
uint32_t entry
Definition: isohybrid.c:63
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
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
static void root_free(IN nfs41_root *root)
Definition: namespace.c:76
static int referral_mount_location(IN nfs41_root *root, IN const fs_location4 *loc, OUT nfs41_client **client_out)
Definition: namespace.c:437
void nfs41_root_ref(IN nfs41_root *root)
Definition: namespace.c:92
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
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
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
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
#define NSLVL
Definition: namespace.c:30
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
static int cl_addr_compare(IN const struct list_entry *entry, IN const void *value)
Definition: namespace.c:117
#define client_entry(pos)
Definition: namespace.c:33
static int cl_exid_compare(IN const struct list_entry *entry, IN const void *value)
Definition: namespace.c:176
int nfs41_session_set_lease(IN nfs41_session *session, IN uint32_t lease_time)
int nfs41_client_owner(IN const char *name, IN uint32_t sec_flavor, OUT client_owner4 *owner)
Definition: nfs41_client.c:358
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
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
int nfs41_session_create(IN nfs41_client *client, IN nfs41_session **session_out)
void nfs41_rpc_clnt_free(IN nfs41_rpc_clnt *rpc)
Definition: nfs41_rpc.c:243
void nfs41_client_free(IN nfs41_client *client)
Definition: nfs41_client.c:206
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)
@ FATTR4_WORD0_LEASE_TIME
Definition: nfs41_const.h:217
@ NFS4ERR_NOTSUPP
Definition: nfs41_const.h:109
#define NFS4_OPAQUE_LIMIT
Definition: nfs41_const.h:31
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
enum nfsstat4 nfs41_reclaim_complete(IN nfs41_session *session)
Definition: nfs41_ops.c:268
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
@ EXCHGID4_FLAG_MASK_PNFS
Definition: nfs41_ops.h:104
@ EXCHGID4_FLAG_USE_PNFS_DS
Definition: nfs41_ops.h:102
sec_flavor
Definition: nfs41_ops.h:861
long LONG
Definition: pedump.c:60
#define dprintf
Definition: regdump.c:33
static FILE * out
Definition: regtests2xml.c:44
#define calloc
Definition: rosglue.h:14
static FILE * client
Definition: client.c:41
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
const multi_addr4 * addrs
Definition: namespace.c:113
uint32_t roles
Definition: namespace.c:114
const nfs41_exchange_id_res * exchangeid
Definition: namespace.c:172
uint32_t roles
Definition: namespace.c:173
unsigned int count
Definition: notification.c:64
Definition: list.h:27
Definition: name.c:39
Definition: ps.c:97
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40
Definition: pdh_main.c:94
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define ERROR_BAD_NETPATH
Definition: winerror.h:145
#define ERROR_BAD_NET_RESP
Definition: winerror.h:150
#define ERROR_BAD_NET_NAME
Definition: winerror.h:159