1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
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.
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.
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
26 #include "nfs41_ops.h"
27 #include "nfs41_callback.h"
28 #include "daemon_debug.h"
31 #define FDLVL 2 /* dprintf level for file device logging */
34 /* pnfs_file_device_list */
35 struct pnfs_file_device_list
{
36 struct list_entry head
;
37 CRITICAL_SECTION lock
;
40 #define device_entry(pos) list_container(pos, pnfs_file_device, entry)
43 static enum pnfs_status
file_device_create(
44 IN
const unsigned char *deviceid
,
45 IN
struct pnfs_file_device_list
*devices
,
46 OUT pnfs_file_device
**device_out
)
48 enum pnfs_status status
= PNFS_SUCCESS
;
49 pnfs_file_device
*device
;
51 device
= calloc(1, sizeof(pnfs_file_device
));
53 status
= PNFSERR_RESOURCES
;
57 memcpy(device
->device
.deviceid
, deviceid
, PNFS_DEVICEID_SIZE
);
58 device
->devices
= devices
;
59 InitializeCriticalSection(&device
->device
.lock
);
65 static void file_device_free(
66 IN pnfs_file_device
*device
)
68 free(device
->servers
.arr
);
69 free(device
->stripes
.arr
);
70 DeleteCriticalSection(&device
->device
.lock
);
74 static int deviceid_compare(
75 const struct list_entry
*entry
,
78 const pnfs_file_device
*device
= device_entry(entry
);
79 return memcmp(device
->device
.deviceid
, deviceid
, PNFS_DEVICEID_SIZE
);
82 static enum pnfs_status
file_device_find_or_create(
83 IN
const unsigned char *deviceid
,
84 IN
struct pnfs_file_device_list
*devices
,
85 OUT pnfs_file_device
**device_out
)
87 struct list_entry
*entry
;
88 enum pnfs_status status
;
90 dprintf(FDLVL
, "--> pnfs_file_device_find_or_create()\n");
92 EnterCriticalSection(&devices
->lock
);
94 /* search for an existing device */
95 entry
= list_search(&devices
->head
, deviceid
, deviceid_compare
);
97 /* create a new device */
98 pnfs_file_device
*device
;
99 status
= file_device_create(deviceid
, devices
, &device
);
100 if (status
== PNFS_SUCCESS
) {
101 /* add it to the list */
102 list_add_tail(&devices
->head
, &device
->entry
);
103 *device_out
= device
;
105 dprintf(FDLVL
, "<-- pnfs_file_device_find_or_create() "
106 "returning new device %p\n", device
);
108 dprintf(FDLVL
, "<-- pnfs_file_device_find_or_create() "
109 "returning %s\n", pnfs_error_string(status
));
112 *device_out
= device_entry(entry
);
113 status
= PNFS_SUCCESS
;
115 dprintf(FDLVL
, "<-- pnfs_file_device_find_or_create() "
116 "returning existing device %p\n", *device_out
);
119 LeaveCriticalSection(&devices
->lock
);
124 enum pnfs_status
pnfs_file_device_list_create(
125 OUT
struct pnfs_file_device_list
**devices_out
)
127 enum pnfs_status status
= PNFS_SUCCESS
;
128 struct pnfs_file_device_list
*devices
;
130 devices
= calloc(1, sizeof(struct pnfs_file_device_list
));
131 if (devices
== NULL
) {
132 status
= PNFSERR_RESOURCES
;
136 list_init(&devices
->head
);
137 InitializeCriticalSection(&devices
->lock
);
139 *devices_out
= devices
;
144 void pnfs_file_device_list_free(
145 IN
struct pnfs_file_device_list
*devices
)
147 struct list_entry
*entry
, *tmp
;
149 EnterCriticalSection(&devices
->lock
);
151 list_for_each_tmp(entry
, tmp
, &devices
->head
)
152 file_device_free(device_entry(entry
));
154 LeaveCriticalSection(&devices
->lock
);
155 DeleteCriticalSection(&devices
->lock
);
159 void pnfs_file_device_list_invalidate(
160 IN
struct pnfs_file_device_list
*devices
)
162 struct list_entry
*entry
, *tmp
;
163 pnfs_file_device
*device
;
165 dprintf(FDLVL
, "--> pnfs_file_device_list_invalidate()\n");
167 EnterCriticalSection(&devices
->lock
);
169 list_for_each_tmp(entry
, tmp
, &devices
->head
) {
170 device
= device_entry(entry
);
171 EnterCriticalSection(&device
->device
.lock
);
172 /* if there are layouts still using the device, flag it
173 * as revoked and clean up on last reference */
174 if (device
->device
.layout_count
) {
175 device
->device
.status
|= PNFS_DEVICE_REVOKED
;
176 LeaveCriticalSection(&device
->device
.lock
);
178 LeaveCriticalSection(&device
->device
.lock
);
179 /* no layouts are using it, so it's safe to free */
181 file_device_free(device
);
185 LeaveCriticalSection(&devices
->lock
);
187 dprintf(FDLVL
, "<-- pnfs_file_device_list_invalidate()\n");
191 /* pnfs_file_device */
192 enum pnfs_status
pnfs_file_device_get(
193 IN nfs41_session
*session
,
194 IN
struct pnfs_file_device_list
*devices
,
195 IN
unsigned char *deviceid
,
196 OUT pnfs_file_device
**device_out
)
198 pnfs_file_device
*device
;
199 enum pnfs_status status
;
200 enum nfsstat4 nfsstat
;
202 dprintf(FDLVL
, "--> pnfs_file_device_get()\n");
204 status
= file_device_find_or_create(deviceid
, devices
, &device
);
208 EnterCriticalSection(&device
->device
.lock
);
210 /* don't give out a device that's been revoked */
211 if (device
->device
.status
& PNFS_DEVICE_REVOKED
)
212 status
= PNFSERR_NO_DEVICE
;
213 else if (device
->device
.status
& PNFS_DEVICE_GRANTED
)
214 status
= PNFS_SUCCESS
;
216 nfsstat
= pnfs_rpc_getdeviceinfo(session
, deviceid
, device
);
217 if (nfsstat
== NFS4_OK
) {
218 device
->device
.status
= PNFS_DEVICE_GRANTED
;
219 status
= PNFS_SUCCESS
;
221 dprintf(FDLVL
, "Received device info:\n");
222 dprint_device(FDLVL
, device
);
224 status
= PNFSERR_NO_DEVICE
;
226 eprintf("pnfs_rpc_getdeviceinfo() failed with %s\n",
227 nfs_error_string(nfsstat
));
231 if (status
== PNFS_SUCCESS
) {
232 device
->device
.layout_count
++;
233 dprintf(FDLVL
, "pnfs_file_device_get() -> %u\n",
234 device
->device
.layout_count
);
235 *device_out
= device
;
238 LeaveCriticalSection(&device
->device
.lock
);
240 dprintf(FDLVL
, "<-- pnfs_file_device_get() returning %s\n",
241 pnfs_error_string(status
));
245 void pnfs_file_device_put(
246 IN pnfs_file_device
*device
)
249 EnterCriticalSection(&device
->device
.lock
);
250 count
= --device
->device
.layout_count
;
251 dprintf(FDLVL
, "pnfs_file_device_put() -> %u\n", count
);
253 /* if the device was revoked, remove/free the device on last reference */
254 if (count
== 0 && device
->device
.status
& PNFS_DEVICE_REVOKED
) {
255 EnterCriticalSection(&device
->devices
->lock
);
256 list_remove(&device
->entry
);
257 LeaveCriticalSection(&device
->devices
->lock
);
259 LeaveCriticalSection(&device
->device
.lock
);
261 file_device_free(device
);
262 dprintf(FDLVL
, "revoked file device freed after last reference\n");
264 LeaveCriticalSection(&device
->device
.lock
);
268 static enum pnfs_status
data_client_status(
269 IN pnfs_data_server
*server
,
270 OUT nfs41_client
**client_out
)
272 enum pnfs_status status
= PNFSERR_NOT_CONNECTED
;
274 if (server
->client
) {
275 dprintf(FDLVL
, "pnfs_data_server_client() returning "
276 "existing client %llu\n", server
->client
->clnt_id
);
277 *client_out
= server
->client
;
278 status
= PNFS_SUCCESS
;
283 enum pnfs_status
pnfs_data_server_client(
285 IN pnfs_data_server
*server
,
286 IN
uint32_t default_lease
,
287 OUT nfs41_client
**client_out
)
290 enum pnfs_status pnfsstat
;
292 dprintf(FDLVL
, "--> pnfs_data_server_client('%s')\n",
293 server
->addrs
.arr
[0].uaddr
);
295 /* if we've already created the client, return it */
296 AcquireSRWLockShared(&server
->lock
);
297 pnfsstat
= data_client_status(server
, client_out
);
298 ReleaseSRWLockShared(&server
->lock
);
303 AcquireSRWLockExclusive(&server
->lock
);
305 pnfsstat
= data_client_status(server
, client_out
);
307 status
= nfs41_root_mount_addrs(root
, &server
->addrs
, 1, default_lease
,
310 dprintf(FDLVL
, "data_client_create('%s') failed with %d\n",
311 server
->addrs
.arr
[0].uaddr
, status
);
313 *client_out
= server
->client
;
314 pnfsstat
= PNFS_SUCCESS
;
316 dprintf(FDLVL
, "pnfs_data_server_client() returning new client "
317 "%llu\n", server
->client
->clnt_id
);
321 ReleaseSRWLockExclusive(&server
->lock
);
327 /* CB_NOTIFY_DEVICEID */
328 enum pnfs_status
pnfs_file_device_notify(
329 IN
struct pnfs_file_device_list
*devices
,
330 IN
const struct notify_deviceid4
*change
)
332 struct list_entry
*entry
;
333 enum pnfs_status status
= PNFSERR_NO_DEVICE
;
335 dprintf(FDLVL
, "--> pnfs_file_device_notify(%u, %0llX:%0llX)\n",
336 change
->type
, change
->deviceid
);
338 if (change
->layouttype
!= PNFS_LAYOUTTYPE_FILE
) {
339 status
= PNFSERR_NOT_SUPPORTED
;
343 EnterCriticalSection(&devices
->lock
);
345 entry
= list_search(&devices
->head
, change
->deviceid
, deviceid_compare
);
347 dprintf(FDLVL
, "found file device %p\n", device_entry(entry
));
349 if (change
->type
== NOTIFY_DEVICEID4_CHANGE
) {
350 /* if (change->immediate) ... */
351 dprintf(FDLVL
, "CHANGE (%u)\n", change
->immediate
);
352 } else if (change
->type
== NOTIFY_DEVICEID4_DELETE
) {
353 /* This notification MUST NOT be sent if the client
354 * has a layout that refers to the device ID. */
355 dprintf(FDLVL
, "DELETE\n");
357 status
= PNFS_SUCCESS
;
360 LeaveCriticalSection(&devices
->lock
);
362 dprintf(FDLVL
, "<-- pnfs_file_device_notify() returning %s\n",
363 pnfs_error_string(status
));