Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / vol / fssync-server.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 *
9 * Portions Copyright (c) 2006-2010 Sine Nomine Associates
10 */
11
12 /*
13 System: VICE-TWO
14 Module: fssync.c
15 Institution: The Information Technology Center, Carnegie-Mellon University
16
17 */
18 #ifndef AFS_PTHREAD_ENV
19 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
20
21 /*
22 * stack size increased from 8K because the HP machine seemed to have trouble
23 * with the smaller stack
24 */
25 #define USUAL_STACK_SIZE (24 * 1024)
26 #endif /* !AFS_PTHREAD_ENV */
27
28 /*
29 fssync-server.c
30 File server synchronization with external volume utilities.
31 server-side implementation
32 */
33
34 /* This controls the size of an fd_set; it must be defined early before
35 * the system headers define that type and the macros that operate on it.
36 * Its value should be as large as the maximum file descriptor limit we
37 * are likely to run into on any platform. Right now, that is 65536
38 * which is the default hard fd limit on Solaris 9 */
39 #ifndef _WIN32
40 #define FD_SETSIZE 65536
41 #endif
42
43 #include <afsconfig.h>
44 #include <afs/param.h>
45
46 #include <roken.h>
47
48 #include <afs/opr.h>
49 #ifdef AFS_PTHREAD_ENV
50 # include <opr/lock.h>
51 #endif
52 #include <afs/afsint.h>
53 #include <rx/rx_queue.h>
54 #include "nfs.h"
55 #include <afs/errors.h>
56 #include "daemon_com.h"
57 #include "daemon_com_inline.h"
58 #include "fssync.h"
59 #include "fssync_inline.h"
60 #include "salvsync.h"
61 #include "lwp.h"
62 #include "lock.h"
63 #include <afs/afssyscalls.h>
64 #include "ihandle.h"
65 #include "vnode.h"
66 #include "volume.h"
67 #include "volume_inline.h"
68 #include "partition.h"
69 #include "vg_cache.h"
70 #include "common.h"
71
72 #ifdef HAVE_POLL
73 #include <sys/poll.h>
74 #endif /* HAVE_POLL */
75
76 #ifdef USE_UNIX_SOCKETS
77 #include <sys/un.h>
78 #include <afs/afsutil.h>
79 #endif /* USE_UNIX_SOCKETS */
80
81 #ifdef FSSYNC_BUILD_SERVER
82
83 int (*V_BreakVolumeCallbacks) (VolumeId volume);
84
85 #define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
86 * move = dump+restore can run on single server */
87 #define MAXOFFLINEVOLUMES 128 /* This needs to be as big as the maximum
88 * number that would be offline for 1 operation.
89 * Current winner is salvage, which needs all
90 * cloned read-only copies offline when salvaging
91 * a single read-write volume */
92
93
94
95 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
96
97 /**
98 * fssync server socket handle.
99 */
100 static SYNC_server_state_t fssync_server_state =
101 { OSI_NULLSOCKET, /* file descriptor */
102 FSSYNC_ENDPOINT_DECL, /* server endpoint */
103 FSYNC_PROTO_VERSION, /* protocol version */
104 5, /* bind() retry limit */
105 100, /* listen() queue depth */
106 "FSSYNC", /* protocol name string */
107 };
108
109 #ifdef AFS_DEMAND_ATTACH_FS
110 /**
111 * a queue of volume pointers to salvage in the background.
112 */
113 struct fsync_salv_node {
114 struct rx_queue q;
115 Volume *vp; /**< volume to salvage */
116 unsigned char update_salv_prio; /**< whether we should update the salvage priority or not */
117 };
118 static struct {
119 struct rx_queue head;
120 pthread_cond_t cv;
121 } fsync_salv;
122
123 static void * FSYNC_salvageThread(void *);
124 static void FSYNC_backgroundSalvage(Volume *vp);
125 #endif /* AFS_DEMAND_ATTACH_FS */
126
127 /* Forward declarations */
128 static void * FSYNC_sync(void *);
129 static void FSYNC_newconnection(osi_socket afd);
130 static void FSYNC_com(osi_socket fd);
131 static void FSYNC_Drop(osi_socket fd);
132 static void AcceptOn(void);
133 static void AcceptOff(void);
134 static void InitHandler(void);
135 static int AddHandler(osi_socket fd, void (*aproc)(osi_socket));
136 static int FindHandler(osi_socket afd);
137 static int FindHandler_r(osi_socket afd);
138 static int RemoveHandler(osi_socket afd);
139 #if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
140 static void CallHandler(struct pollfd *fds, int nfds, int mask);
141 static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
142 #else
143 static void CallHandler(fd_set * fdsetp);
144 static void GetHandler(fd_set * fdsetp, int *maxfdp);
145 #endif
146
147 static afs_int32 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
148
149 #ifdef AFS_DEMAND_ATTACH_FS
150 static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
151 #endif
152 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
153 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
154 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
155 static afs_int32 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * com, SYNC_response * res);
156 static afs_int32 FSYNC_com_VolDone(FSSYNC_VolOp_command * com, SYNC_response * res);
157 static afs_int32 FSYNC_com_VolQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
158 static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
159 #ifdef AFS_DEMAND_ATTACH_FS
160 static afs_int32 FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res);
161 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
162 static afs_int32 FSYNC_com_VGQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
163 static afs_int32 FSYNC_com_VGScan(FSSYNC_VolOp_command * com, SYNC_response * res);
164 static afs_int32 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res);
165 #endif /* AFS_DEMAND_ATTACH_FS */
166
167 static afs_int32 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res);
168
169 static afs_int32 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
170
171 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
172
173 #ifdef AFS_DEMAND_ATTACH_FS
174 static afs_int32 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res);
175 static afs_int32 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res);
176 static afs_int32 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res);
177 static afs_int32 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res);
178 #endif
179
180 static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
181
182 static int FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon);
183
184
185 /*
186 * This lock controls access to the handler array. The overhead
187 * is minimal in non-preemptive environments.
188 */
189 struct Lock FSYNC_handler_lock;
190
191 void
192 FSYNC_fsInit(void)
193 {
194 #ifdef AFS_PTHREAD_ENV
195 pthread_t tid;
196 pthread_attr_t tattr;
197 #else /* AFS_PTHREAD_ENV */
198 PROCESS pid;
199 #endif /* AFS_PTHREAD_ENV */
200
201 Lock_Init(&FSYNC_handler_lock);
202
203 #ifdef AFS_PTHREAD_ENV
204 opr_Verify(pthread_attr_init(&tattr) == 0);
205 opr_Verify(pthread_attr_setdetachstate(&tattr,
206 PTHREAD_CREATE_DETACHED) == 0);
207 opr_Verify(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
208 #else /* AFS_PTHREAD_ENV */
209 opr_Verify(LWP_CreateProcess(FSYNC_sync, USUAL_STACK_SIZE,
210 USUAL_PRIORITY, NULL,
211 "FSYNC_sync", &pid) == LWP_SUCCESS);
212 #endif /* AFS_PTHREAD_ENV */
213
214 #ifdef AFS_DEMAND_ATTACH_FS
215 queue_Init(&fsync_salv.head);
216 opr_cv_init(&fsync_salv.cv);
217 opr_Verify(pthread_create(&tid, &tattr, FSYNC_salvageThread, NULL) == 0);
218 #endif /* AFS_DEMAND_ATTACH_FS */
219 }
220
221 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
222 static struct pollfd FSYNC_readfds[MAXHANDLERS];
223 #else
224 static fd_set FSYNC_readfds;
225 #endif
226
227
228 static void *
229 FSYNC_sync(void * args)
230 {
231 extern int VInit;
232 int code;
233 #ifdef AFS_PTHREAD_ENV
234 int tid;
235 #endif
236 SYNC_server_state_t * state = &fssync_server_state;
237 #ifdef AFS_DEMAND_ATTACH_FS
238 VThreadOptions_t * thread_opts;
239 int min_vinit = 2;
240 #else
241 /*
242 * For non-DAFS, only wait until we begin attaching volumes (instead
243 * of waiting until all volumes are attached), since it can take
244 * awhile until VInit == 2.
245 */
246 int min_vinit = 1;
247 #endif /* AFS_DEMAND_ATTACH_FS */
248
249 /* we must not be called before vol package initialization, since we use
250 * vol package mutexes and conds etc */
251 opr_Assert(VInit);
252
253 SYNC_getAddr(&state->endpoint, &state->addr);
254 SYNC_cleanupSock(state);
255
256 #ifndef AFS_NT40_ENV
257 (void)signal(SIGPIPE, SIG_IGN);
258 #endif
259
260 #ifdef AFS_PTHREAD_ENV
261 /* set our 'thread-id' so that the host hold table works */
262 tid = rx_SetThreadNum();
263 Log("Set thread id %d for FSYNC_sync\n", tid);
264 afs_pthread_setname_self("FSYNC_sync");
265 #endif /* AFS_PTHREAD_ENV */
266
267 VOL_LOCK;
268
269 while (VInit < min_vinit) {
270 /* Let somebody else run until all volumes have been preattached
271 * (DAFS), or we have started attaching volumes (non-DAFS). This
272 * doesn't mean that all volumes have been attached.
273 */
274 #ifdef AFS_PTHREAD_ENV
275 VOL_CV_WAIT(&vol_vinit_cond);
276 #else /* AFS_PTHREAD_ENV */
277 LWP_DispatchProcess();
278 #endif /* AFS_PTHREAD_ENV */
279 }
280
281 VOL_UNLOCK;
282
283 state->fd = SYNC_getSock(&state->endpoint);
284 code = SYNC_bindSock(state);
285 opr_Assert(!code);
286
287 #ifdef AFS_DEMAND_ATTACH_FS
288 /*
289 * make sure the volume package is incapable of recursively executing
290 * salvsync calls on this thread, since there is a possibility of
291 * deadlock.
292 */
293 thread_opts = malloc(sizeof(VThreadOptions_t));
294 if (thread_opts == NULL) {
295 Log("failed to allocate memory for thread-specific volume package options structure\n");
296 return NULL;
297 }
298 memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
299 thread_opts->disallow_salvsync = 1;
300 opr_Verify(pthread_setspecific(VThread_key, thread_opts) == 0);
301
302 code = VVGCache_PkgInit();
303 opr_Assert(code == 0);
304 #endif
305
306 InitHandler();
307 AcceptOn();
308
309 for (;;) {
310 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
311 int nfds;
312 GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
313 if (poll(FSYNC_readfds, nfds, -1) >=1)
314 CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
315 #else
316 int maxfd;
317 #ifdef AFS_PTHREAD_ENV
318 struct timeval s_timeout;
319 #endif
320 GetHandler(&FSYNC_readfds, &maxfd);
321 /* Note: check for >= 1 below is essential since IOMGR_select
322 * doesn't have exactly same semantics as select.
323 */
324 #ifdef AFS_PTHREAD_ENV
325 s_timeout.tv_sec = SYNC_SELECT_TIMEOUT;
326 s_timeout.tv_usec = 0;
327 if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, &s_timeout) >= 1)
328 #else /* AFS_PTHREAD_ENV */
329 if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
330 #endif /* AFS_PTHREAD_ENV */
331 CallHandler(&FSYNC_readfds);
332 #endif
333 }
334 AFS_UNREACHED(return(NULL)); /* hush now, little gcc */
335 }
336
337 #ifdef AFS_DEMAND_ATTACH_FS
338 /**
339 * thread for salvaging volumes in the background.
340 *
341 * Since FSSYNC handlers cannot issue SALVSYNC requests in order to avoid
342 * deadlock issues, this thread exists so code in the FSSYNC handler thread
343 * can hand off volumes to be salvaged in the background.
344 *
345 * @param[in] args unused
346 *
347 * @note DEMAND_ATTACH_FS only
348 */
349 static void *
350 FSYNC_salvageThread(void * args)
351 {
352 Volume *vp;
353 struct fsync_salv_node *node;
354
355 VOL_LOCK;
356
357 for (;;) {
358 while (queue_IsEmpty(&fsync_salv.head)) {
359 VOL_CV_WAIT(&fsync_salv.cv);
360 }
361
362 node = queue_First(&fsync_salv.head, fsync_salv_node);
363 queue_Remove(node);
364
365 vp = node->vp;
366 if (node->update_salv_prio) {
367 if (VUpdateSalvagePriority_r(vp)) {
368 ViceLog(0, ("FSYNC_salvageThread: unable to raise salvage priority "
369 "for volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(vp->hashid)));
370 }
371 }
372
373 free(node);
374 node = NULL;
375
376 VCancelReservation_r(vp);
377 }
378
379 AFS_UNREACHED(VOL_UNLOCK);
380 AFS_UNREACHED(return(NULL));
381 }
382
383 /**
384 * salvage a volume in the background.
385 *
386 * Salvages cannot be scheduled directly from the main FSYNC thread, so
387 * instead call this function to schedule a salvage asynchronously in the
388 * FSYNC_salvageThread thread.
389 *
390 * @param[in] vp volume to pointer to salvage
391 *
392 * @pre VOL_LOCK held
393 *
394 * @note DEMAND_ATTACH_FS only
395 */
396 static void
397 FSYNC_backgroundSalvage(Volume *vp)
398 {
399 struct fsync_salv_node *node;
400 Error ec;
401
402 VCreateReservation_r(vp);
403
404 node = malloc(sizeof(struct fsync_salv_node));
405 node->vp = vp;
406
407 /* Save this value, to know if we should VUpdateSalvagePriority_r.
408 * We need to save it here, snce VRequestSalvage_r will change it. */
409 node->update_salv_prio = vp->salvage.requested;
410
411 if (VRequestSalvage_r(&ec, vp, SALVSYNC_ERROR, 0)) {
412 ViceLog(0, ("FSYNC_backgroundSalvage: unable to request salvage for volume %" AFS_VOLID_FMT "\n",
413 afs_printable_VolumeId_lu(vp->hashid)));
414 }
415
416 queue_Append(&fsync_salv.head, node);
417 opr_cv_broadcast(&fsync_salv.cv);
418 }
419 #endif /* AFS_DEMAND_ATTACH_FS */
420
421 static void
422 FSYNC_newconnection(osi_socket afd)
423 {
424 #ifdef USE_UNIX_SOCKETS
425 struct sockaddr_un other;
426 #else /* USE_UNIX_SOCKETS */
427 struct sockaddr_in other;
428 #endif
429 osi_socket fd;
430 socklen_t junk;
431 junk = sizeof(other);
432 fd = accept(afd, (struct sockaddr *)&other, &junk);
433 if (fd == OSI_NULLSOCKET) {
434 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
435 opr_abort();
436 } else if (!AddHandler(fd, FSYNC_com)) {
437 AcceptOff();
438 opr_Verify(AddHandler(fd, FSYNC_com));
439 }
440 }
441
442 /* this function processes commands from an fssync file descriptor (fd) */
443 afs_int32 FS_cnt = 0;
444 static void
445 FSYNC_com(osi_socket fd)
446 {
447 SYNC_command com;
448 SYNC_response res;
449 SYNC_PROTO_BUF_DECL(com_buf);
450 SYNC_PROTO_BUF_DECL(res_buf);
451
452 memset(&res.hdr, 0, sizeof(res.hdr));
453
454 com.payload.buf = (void *)com_buf;
455 com.payload.len = SYNC_PROTO_MAX_LEN;
456 res.hdr.response_len = sizeof(res.hdr);
457 res.payload.len = SYNC_PROTO_MAX_LEN;
458 res.payload.buf = (void *)res_buf;
459
460 FS_cnt++;
461 if (SYNC_getCom(&fssync_server_state, fd, &com)) {
462 Log("FSYNC_com: read failed; dropping connection (cnt=%d)\n", FS_cnt);
463 FSYNC_Drop(fd);
464 return;
465 }
466
467 if (com.recv_len < sizeof(com.hdr)) {
468 Log("FSSYNC_com: invalid protocol message length (%u)\n", com.recv_len);
469 res.hdr.response = SYNC_COM_ERROR;
470 res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
471 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
472 goto respond;
473 }
474
475 if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
476 Log("FSYNC_com: invalid protocol version (%u)\n", com.hdr.proto_version);
477 res.hdr.response = SYNC_COM_ERROR;
478 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
479 goto respond;
480 }
481
482 if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
483 res.hdr.response = SYNC_OK;
484 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
485
486 /* don't respond, just drop; senders of SYNC_COM_CHANNEL_CLOSE
487 * never wait for a response. */
488 goto done;
489 }
490
491 ViceLog(125, ("FSYNC_com: from fd %d got command %ld (%s) reason %ld (%s) "
492 "pt %ld (%s) pid %ld\n", (int)fd,
493 afs_printable_int32_ld(com.hdr.command),
494 FSYNC_com2string(com.hdr.command),
495 afs_printable_int32_ld(com.hdr.reason),
496 FSYNC_reason2string(com.hdr.reason),
497 afs_printable_int32_ld(com.hdr.programType),
498 VPTypeToString(com.hdr.programType),
499 afs_printable_int32_ld(com.hdr.pid)));
500
501 res.hdr.com_seq = com.hdr.com_seq;
502
503 VOL_LOCK;
504 switch (com.hdr.command) {
505 case FSYNC_VOL_ON:
506 case FSYNC_VOL_ATTACH:
507 case FSYNC_VOL_LEAVE_OFF:
508 case FSYNC_VOL_OFF:
509 case FSYNC_VOL_FORCE_ERROR:
510 case FSYNC_VOL_LISTVOLUMES:
511 case FSYNC_VOL_NEEDVOLUME:
512 case FSYNC_VOL_MOVE:
513 case FSYNC_VOL_BREAKCBKS:
514 case FSYNC_VOL_DONE:
515 case FSYNC_VOL_QUERY:
516 case FSYNC_VOL_QUERY_HDR:
517 #ifdef AFS_DEMAND_ATTACH_FS
518 case FSYNC_VOL_QUERY_VOP:
519 case FSYNC_VG_QUERY:
520 case FSYNC_VG_SCAN:
521 case FSYNC_VG_SCAN_ALL:
522 #endif
523 res.hdr.response = FSYNC_com_VolOp(fd, &com, &res);
524 break;
525 case FSYNC_VOL_STATS_GENERAL:
526 case FSYNC_VOL_STATS_VICEP:
527 case FSYNC_VOL_STATS_HASH:
528 case FSYNC_VOL_STATS_HDR:
529 case FSYNC_VOL_STATS_VLRU:
530 res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
531 break;
532 case FSYNC_VOL_QUERY_VNODE:
533 res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
534 break;
535 #ifdef AFS_DEMAND_ATTACH_FS
536 case FSYNC_VG_ADD:
537 case FSYNC_VG_DEL:
538 res.hdr.response = FSYNC_com_VGUpdate(fd, &com, &res);
539 break;
540 #endif
541 default:
542 res.hdr.response = SYNC_BAD_COMMAND;
543 break;
544 }
545 VOL_UNLOCK;
546
547 ViceLog(125, ("FSYNC_com: fd %d responding with code %ld (%s) reason %ld "
548 "(%s)\n", (int)fd,
549 afs_printable_int32_ld(res.hdr.response),
550 SYNC_res2string(res.hdr.response),
551 afs_printable_int32_ld(res.hdr.reason),
552 FSYNC_reason2string(res.hdr.reason)));
553
554 respond:
555 SYNC_putRes(&fssync_server_state, fd, &res);
556
557 done:
558 if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
559 FSYNC_Drop(fd);
560 }
561 }
562
563 static afs_int32
564 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
565 {
566 int i;
567 afs_int32 code = SYNC_OK;
568 FSSYNC_VolOp_command vcom;
569
570 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VolOp_hdr))) {
571 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
572 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
573 return SYNC_COM_ERROR;
574 }
575
576 vcom.hdr = &com->hdr;
577 vcom.vop = (FSSYNC_VolOp_hdr *) com->payload.buf;
578 vcom.com = com;
579
580 vcom.volumes = OfflineVolumes[FindHandler(fd)];
581 for (vcom.v = NULL, i = 0; i < MAXOFFLINEVOLUMES; i++) {
582 if ((vcom.volumes[i].volumeID == vcom.vop->volume) &&
583 (strncmp(vcom.volumes[i].partName, vcom.vop->partName,
584 sizeof(vcom.volumes[i].partName)) == 0)) {
585 vcom.v = &vcom.volumes[i];
586 break;
587 }
588 }
589
590 ViceLog(125, ("FSYNC_com_VolOp: fd %d got command for vol %lu part %.16s\n",
591 (int)fd, afs_printable_uint32_lu(vcom.vop->volume),
592 vcom.vop->partName));
593
594 switch (com->hdr.command) {
595 case FSYNC_VOL_ON:
596 case FSYNC_VOL_ATTACH:
597 case FSYNC_VOL_LEAVE_OFF:
598 code = FSYNC_com_VolOn(&vcom, res);
599 break;
600 case FSYNC_VOL_OFF:
601 case FSYNC_VOL_NEEDVOLUME:
602 code = FSYNC_com_VolOff(&vcom, res);
603 break;
604 case FSYNC_VOL_LISTVOLUMES:
605 code = SYNC_OK;
606 break;
607 case FSYNC_VOL_MOVE:
608 code = FSYNC_com_VolMove(&vcom, res);
609 break;
610 case FSYNC_VOL_BREAKCBKS:
611 code = FSYNC_com_VolBreakCBKs(&vcom, res);
612 break;
613 case FSYNC_VOL_DONE:
614 code = FSYNC_com_VolDone(&vcom, res);
615 break;
616 case FSYNC_VOL_QUERY:
617 code = FSYNC_com_VolQuery(&vcom, res);
618 break;
619 case FSYNC_VOL_QUERY_HDR:
620 code = FSYNC_com_VolHdrQuery(&vcom, res);
621 break;
622 #ifdef AFS_DEMAND_ATTACH_FS
623 case FSYNC_VOL_FORCE_ERROR:
624 code = FSYNC_com_VolError(&vcom, res);
625 break;
626 case FSYNC_VOL_QUERY_VOP:
627 code = FSYNC_com_VolOpQuery(&vcom, res);
628 break;
629 case FSYNC_VG_QUERY:
630 code = FSYNC_com_VGQuery(&vcom, res);
631 break;
632 case FSYNC_VG_SCAN:
633 code = FSYNC_com_VGScan(&vcom, res);
634 break;
635 case FSYNC_VG_SCAN_ALL:
636 code = FSYNC_com_VGScanAll(&vcom, res);
637 break;
638 #endif /* AFS_DEMAND_ATTACH_FS */
639 default:
640 code = SYNC_BAD_COMMAND;
641 }
642
643 return code;
644 }
645
646 /**
647 * service an FSYNC request to bring a volume online.
648 *
649 * @param[in] vcom pointer command object
650 * @param[out] res object in which to store response packet
651 *
652 * @return operation status
653 * @retval SYNC_OK volume transitioned online
654 * @retval SYNC_FAILED invalid command protocol message
655 * @retval SYNC_DENIED operation could not be completed
656 *
657 * @note this is an FSYNC RPC server stub
658 *
659 * @note this procedure handles the following FSSYNC command codes:
660 * - FSYNC_VOL_ON
661 * - FSYNC_VOL_ATTACH
662 * - FSYNC_VOL_LEAVE_OFF
663 *
664 * @note the supplementary reason code contains additional details.
665 * When SYNC_DENIED is returned, the specific reason is
666 * placed in the response packet reason field.
667 *
668 * @internal
669 */
670 static afs_int32
671 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
672 {
673 afs_int32 code = SYNC_OK;
674 #ifndef AFS_DEMAND_ATTACH_FS
675 char tvolName[VMAXPATHLEN];
676 #endif
677 Volume * vp;
678 Error error;
679
680 /* Verify the partition name is null terminated. */
681 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
682 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
683 code = SYNC_FAILED;
684 goto done;
685 }
686
687 /* so, we need to attach the volume */
688
689 #ifdef AFS_DEMAND_ATTACH_FS
690 /* Verify the partition name is not empty. */
691 if (*vcom->vop->partName == 0) {
692 res->hdr.reason = FSYNC_BAD_PART;
693 code = SYNC_FAILED;
694 goto done;
695 }
696
697 /* check DAFS permissions */
698 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
699 if (vp &&
700 FSYNC_partMatch(vcom, vp, 1) &&
701 vp->pending_vol_op &&
702 (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
703 /* a different program has this volume checked out. deny. */
704 Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
705 "state for volume %" AFS_VOLID_FMT " using command code %u while the volume is "
706 "checked out by program type %u for command code %u.\n",
707 vcom->hdr->programType,
708 afs_printable_VolumeId_lu(vcom->vop->volume),
709 vcom->hdr->command,
710 vp->pending_vol_op->com.programType,
711 vp->pending_vol_op->com.command);
712 code = SYNC_DENIED;
713 res->hdr.reason = FSYNC_EXCLUSIVE;
714 goto done;
715 }
716 #endif
717
718 if (vcom->v)
719 vcom->v->volumeID = 0;
720
721
722 if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
723 /* nothing much to do if we're leaving the volume offline */
724 #ifdef AFS_DEMAND_ATTACH_FS
725 if (vp) {
726 VCreateReservation_r(vp);
727 VWaitExclusiveState_r(vp);
728 }
729 if (vp && V_attachState(vp) != VOL_STATE_DELETED) {
730 if (FSYNC_partMatch(vcom, vp, 1)) {
731 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
732 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
733 VChangeState_r(vp, VOL_STATE_UNATTACHED);
734 VDeregisterVolOp_r(vp);
735 } else {
736 code = SYNC_DENIED;
737 res->hdr.reason = FSYNC_BAD_STATE;
738 }
739 } else {
740 code = SYNC_DENIED;
741 res->hdr.reason = FSYNC_WRONG_PART;
742 }
743 } else {
744 code = SYNC_FAILED;
745 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
746 }
747
748 if (vp) {
749 VCancelReservation_r(vp);
750 vp = NULL;
751 }
752 #endif
753 goto done;
754 }
755
756 #ifdef AFS_DEMAND_ATTACH_FS
757
758 if (vp &&
759 FSYNC_partMatch(vcom, vp, 0) &&
760 vp->pending_vol_op &&
761 vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningOnline &&
762 V_attachState(vp) == VOL_STATE_ATTACHED) {
763
764 /* noop; the volume stayed online for the volume operation and we were
765 * simply told that the vol op is done. The vp we already have is fine,
766 * so avoid confusing volume routines with trying to preattach an
767 * attached volume. */
768
769 } else {
770 /* first, check to see whether we have such a volume defined */
771 vp = VPreAttachVolumeById_r(&error,
772 vcom->vop->partName,
773 vcom->vop->volume);
774 }
775
776 if (vp) {
777 VCreateReservation_r(vp);
778 VWaitExclusiveState_r(vp);
779 VDeregisterVolOp_r(vp);
780 VCancelReservation_r(vp);
781 vp = NULL;
782 }
783 #else /* !AFS_DEMAND_ATTACH_FS */
784 tvolName[0] = OS_DIRSEPC;
785 snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_printable_VolumeId_lu(vcom->vop->volume));
786 tvolName[sizeof(tvolName)-1] = '\0';
787
788 vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
789 V_VOLUPD);
790 if (vp)
791 VPutVolume_r(vp);
792 #endif /* !AFS_DEMAND_ATTACH_FS */
793 if (error) {
794 code = SYNC_DENIED;
795 res->hdr.reason = error;
796 }
797
798 done:
799 return code;
800 }
801
802 /**
803 * service an FSYNC request to take a volume offline.
804 *
805 * @param[in] vcom pointer command object
806 * @param[out] res object in which to store response packet
807 *
808 * @return operation status
809 * @retval SYNC_OK volume transitioned offline
810 * @retval SYNC_FAILED invalid command protocol message
811 * @retval SYNC_DENIED operation could not be completed
812 *
813 * @note this is an FSYNC RPC server stub
814 *
815 * @note this procedure handles the following FSSYNC command codes:
816 * - FSYNC_VOL_OFF
817 * - FSYNC_VOL_NEEDVOLUME
818 *
819 * @note the supplementary reason code contains additional details.
820 * When SYNC_DENIED is returned, the specific reason is
821 * placed in the response packet reason field.
822 *
823 * @internal
824 */
825 static afs_int32
826 FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
827 {
828 FSSYNC_VolOp_info info;
829 afs_int32 code = SYNC_OK;
830 int i;
831 Volume * vp;
832 Error error;
833 #ifdef AFS_DEMAND_ATTACH_FS
834 Volume *nvp, *rvp = NULL;
835 #endif
836
837 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
838 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
839 code = SYNC_FAILED;
840 goto done;
841 }
842
843 /* not already offline, we need to find a slot for newly offline volume */
844 if (vcom->hdr->programType == debugUtility) {
845 /* debug utilities do not have their operations tracked */
846 vcom->v = NULL;
847 } else {
848 if (!vcom->v) {
849 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
850 if (vcom->volumes[i].volumeID == 0) {
851 vcom->v = &vcom->volumes[i];
852 break;
853 }
854 }
855 }
856 if (!vcom->v) {
857 goto deny;
858 }
859 }
860
861 FSYNC_com_to_info(vcom, &info);
862
863 #ifdef AFS_DEMAND_ATTACH_FS
864 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
865 #else
866 vp = VGetVolume_r(&error, vcom->vop->volume);
867 #endif
868
869 if (vp) {
870 if (!FSYNC_partMatch(vcom, vp, 1)) {
871 /* volume on desired partition is not online, so we
872 * should treat this as an offline volume.
873 */
874 #ifndef AFS_DEMAND_ATTACH_FS
875 VPutVolume_r(vp);
876 #endif
877 vp = NULL;
878 goto done;
879 }
880 }
881
882 #ifdef AFS_DEMAND_ATTACH_FS
883 if (vp) {
884 ProgramType type = (ProgramType) vcom->hdr->programType;
885
886 /* do initial filtering of requests */
887
888 /* enforce mutual exclusion for volume ops */
889 if (vp->pending_vol_op) {
890 if (vp->pending_vol_op->com.programType != type) {
891 if (vp->pending_vol_op->com.command == FSYNC_VOL_OFF &&
892 vp->pending_vol_op->com.reason == FSYNC_SALVAGE) {
893
894 Log("denying offline request for volume %" AFS_VOLID_FMT "; volume is salvaging\n",
895 afs_printable_VolumeId_lu(vp->hashid));
896
897 res->hdr.reason = FSYNC_SALVAGE;
898 goto deny;
899 }
900 Log("volume %" AFS_VOLID_FMT " already checked out\n",
901 afs_printable_VolumeId_lu(vp->hashid));
902 /* XXX debug */
903 Log("vp->vop = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x }, vop = { vol=%" AFS_VOLID_FMT ", part='%s' } }\n",
904 vp->pending_vol_op->com.proto_version,
905 vp->pending_vol_op->com.programType,
906 vp->pending_vol_op->com.command,
907 vp->pending_vol_op->com.reason,
908 vp->pending_vol_op->com.command_len,
909 vp->pending_vol_op->com.flags,
910 afs_printable_VolumeId_lu(vp->pending_vol_op->vop.volume),
911 vp->pending_vol_op->vop.partName );
912 Log("vcom = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x } , vop = { vol=%" AFS_VOLID_FMT ", part='%s' } }\n",
913 vcom->hdr->proto_version,
914 vcom->hdr->programType,
915 vcom->hdr->command,
916 vcom->hdr->reason,
917 vcom->hdr->command_len,
918 vcom->hdr->flags,
919 afs_printable_VolumeId_lu(vcom->vop->volume),
920 vcom->vop->partName);
921 res->hdr.reason = FSYNC_EXCLUSIVE;
922 goto deny;
923 } else {
924 Log("warning: volume %" AFS_VOLID_FMT " recursively checked out by programType id %d\n",
925 afs_printable_VolumeId_lu(vp->hashid), vcom->hdr->programType);
926 }
927 }
928
929 /* wait for exclusive ops, so we have an accurate picture of the
930 * vol attach state */
931 VCreateReservation_r(vp);
932 VWaitExclusiveState_r(vp);
933 rvp = vp;
934
935 /* filter based upon requestor
936 *
937 * volume utilities / volserver are not allowed to check out
938 * volumes which are in an error state
939 *
940 * unknown utility programs will be denied on principal
941 */
942 switch (type) {
943 case salvageServer:
944 case volumeSalvager:
945 /* it is possible for the salvageserver to checkout a
946 * volume for salvage before its scheduling request
947 * has been sent to the salvageserver */
948 if (vp->salvage.requested && !vp->salvage.scheduled) {
949 vp->salvage.scheduled = 1;
950 }
951
952 /* If the volume is in VOL_STATE_SALVAGE_REQ, we need to wait
953 * for the vol to go offline before we can give it away. Also
954 * make sure we don't come out with vp in an excl state. */
955 while (V_attachState(vp) == VOL_STATE_SALVAGE_REQ ||
956 VIsExclusiveState(V_attachState(vp))) {
957
958 VOL_CV_WAIT(&V_attachCV(vp));
959 }
960
961 case debugUtility:
962 break;
963
964 case volumeUtility:
965 case volumeServer:
966 if (VIsSalvaging(vp)) {
967 Log("denying offline request for volume %" AFS_VOLID_FMT "; volume is in salvaging state\n",
968 afs_printable_VolumeId_lu(vp->hashid));
969 res->hdr.reason = FSYNC_SALVAGE;
970
971 /* the volume hasn't been checked out yet by the salvager,
972 * but we think the volume is salvaging; schedule a
973 * a salvage to update the salvage priority */
974 FSYNC_backgroundSalvage(vp);
975
976 goto deny;
977 }
978 if (VIsErrorState(V_attachState(vp))) {
979 goto deny;
980 }
981 break;
982
983 default:
984 Log("bad program type passed to FSSYNC\n");
985 goto deny;
986 }
987
988 /* short circuit for offline volume states
989 * so we can avoid I/O penalty of attachment */
990 switch (V_attachState(vp)) {
991 case VOL_STATE_UNATTACHED:
992 case VOL_STATE_PREATTACHED:
993 case VOL_STATE_SALVAGING:
994 case VOL_STATE_ERROR:
995 /* register the volume operation metadata with the volume
996 *
997 * if the volume is currently pre-attached, attach2()
998 * will evaluate the vol op metadata to determine whether
999 * attaching the volume would be safe */
1000 VRegisterVolOp_r(vp, &info);
1001 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
1002 /* fall through */
1003
1004 case VOL_STATE_DELETED:
1005 goto done;
1006 default:
1007 break;
1008 }
1009
1010 /* convert to heavyweight ref */
1011 nvp = VGetVolumeByVp_r(&error, vp);
1012 if (!nvp) {
1013 /*
1014 * It's possible for VGetVolumeByVp_r to have dropped and
1015 * re-acquired VOL_LOCK, so volume state may have changed
1016 * back to one of the states we tested for above. Since
1017 * GetVolume can return NULL in some of those states, just
1018 * test for the states again here.
1019 */
1020 switch (V_attachState(vp)) {
1021 case VOL_STATE_UNATTACHED:
1022 case VOL_STATE_PREATTACHED:
1023 case VOL_STATE_SALVAGING:
1024 case VOL_STATE_ERROR:
1025 /* register the volume operation metadata with the volume
1026 *
1027 * if the volume is currently pre-attached, attach2()
1028 * will evaluate the vol op metadata to determine whether
1029 * attaching the volume would be safe */
1030 VRegisterVolOp_r(vp, &info);
1031 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
1032 /* fall through */
1033
1034 case VOL_STATE_DELETED:
1035 goto done;
1036 default:
1037 break;
1038 }
1039
1040 Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %" AFS_VOLID_FMT " (state=%u, flags=0x%x)\n",
1041 afs_printable_VolumeId_lu(vcom->vop->volume),
1042 V_attachState(vp), V_attachFlags(vp));
1043 res->hdr.reason = FSYNC_VOL_PKG_ERROR;
1044 goto deny;
1045 } else if (nvp != vp) {
1046 /* i don't think this should ever happen, but just in case... */
1047 Log("FSYNC_com_VolOff: warning: potentially dangerous race detected\n");
1048 vp = nvp;
1049 }
1050
1051 /* kill off lightweight ref to ensure we can't deadlock against ourselves later... */
1052 VCancelReservation_r(rvp);
1053 rvp = NULL;
1054
1055 /* register the volume operation metadata with the volume */
1056 VRegisterVolOp_r(vp, &info);
1057
1058 }
1059 #endif /* AFS_DEMAND_ATTACH_FS */
1060
1061 if (vp) {
1062 if (VVolOpLeaveOnline_r(vp, &info)) {
1063 VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT); /* At least get volume stats right */
1064 if (GetLogLevel() > 0) {
1065 Log("FSYNC: Volume %" AFS_VOLID_FMT " (%s) was left on line for an external %s request\n",
1066 afs_printable_VolumeId_lu(V_id(vp)), V_name(vp),
1067 vcom->hdr->reason == V_CLONE ? "clone" :
1068 vcom->hdr->reason == V_READONLY ? "readonly" :
1069 vcom->hdr->reason == V_DUMP ? "dump" :
1070 vcom->hdr->reason == FSYNC_SALVAGE ? "salvage" :
1071 "UNKNOWN");
1072 }
1073 #ifdef AFS_DEMAND_ATTACH_FS
1074 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
1075 #endif
1076 VPutVolume_r(vp);
1077 } else {
1078 if (VVolOpSetVBusy_r(vp, &info)) {
1079 vp->specialStatus = VBUSY;
1080 }
1081
1082 /* remember what volume we got, so we can keep track of how
1083 * many volumes the volserver or whatever is using. Note that
1084 * vp is valid since leaveonline is only set when vp is valid.
1085 */
1086 if (vcom->v) {
1087 vcom->v->volumeID = vcom->vop->volume;
1088 strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
1089 }
1090
1091 #ifdef AFS_DEMAND_ATTACH_FS
1092 VCreateReservation_r(vp);
1093 VOfflineForVolOp_r(&error, vp, "A volume utility is running.");
1094 if (error==0) {
1095 opr_Assert(vp->nUsers==0);
1096 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
1097 }
1098 else {
1099 VWaitExclusiveState_r(vp);
1100 VDeregisterVolOp_r(vp);
1101 code = SYNC_DENIED;
1102 }
1103 VCancelReservation_r(vp);
1104 #else
1105 VOffline_r(vp, "A volume utility is running.");
1106 #endif
1107 vp = NULL;
1108 }
1109 }
1110 goto done;
1111
1112 deny:
1113 code = SYNC_DENIED;
1114
1115 done:
1116 #ifdef AFS_DEMAND_ATTACH_FS
1117 if (rvp) {
1118 VCancelReservation_r(rvp);
1119 }
1120 #endif
1121 return code;
1122 }
1123
1124 /**
1125 * service an FSYNC request to mark a volume as moved.
1126 *
1127 * @param[in] vcom pointer command object
1128 * @param[out] res object in which to store response packet
1129 *
1130 * @return operation status
1131 * @retval SYNC_OK volume marked as moved to a remote server
1132 * @retval SYNC_FAILED invalid command protocol message
1133 * @retval SYNC_DENIED current volume state does not permit this operation
1134 *
1135 * @note this is an FSYNC RPC server stub
1136 *
1137 * @note this operation also breaks all callbacks for the given volume
1138 *
1139 * @note this procedure handles the following FSSYNC command codes:
1140 * - FSYNC_VOL_MOVE
1141 *
1142 * @note the supplementary reason code contains additional details. For
1143 * instance, SYNC_OK is still returned when the partition specified
1144 * does not match the one registered in the volume object -- reason
1145 * will be FSYNC_WRONG_PART in this case.
1146 *
1147 * @internal
1148 */
1149 static afs_int32
1150 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1151 {
1152 afs_int32 code = SYNC_DENIED;
1153 Error error;
1154 Volume * vp;
1155
1156 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1157 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1158 code = SYNC_FAILED;
1159 goto done;
1160 }
1161
1162 /* Yuch: the "reason" for the move is the site it got moved to... */
1163 /* still set specialStatus so we stop sending back VBUSY.
1164 * also should still break callbacks. Note that I don't know
1165 * how to tell if we should break all or not, so we just do it
1166 * since it doesn't matter much if we do an extra break
1167 * volume callbacks on a volume move within the same server */
1168 #ifdef AFS_DEMAND_ATTACH_FS
1169 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1170 #else
1171 vp = VGetVolume_r(&error, vcom->vop->volume);
1172 #endif
1173 if (vp) {
1174 if (FSYNC_partMatch(vcom, vp, 1)) {
1175 #ifdef AFS_DEMAND_ATTACH_FS
1176 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1177 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
1178 #endif
1179 code = SYNC_OK;
1180 vp->specialStatus = VMOVED;
1181 #ifdef AFS_DEMAND_ATTACH_FS
1182 } else {
1183 res->hdr.reason = FSYNC_BAD_STATE;
1184 }
1185 #endif
1186 } else {
1187 res->hdr.reason = FSYNC_WRONG_PART;
1188 }
1189 #ifndef AFS_DEMAND_ATTACH_FS
1190 VPutVolume_r(vp);
1191 #endif /* !AFS_DEMAND_ATTACH_FS */
1192 } else {
1193 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1194 }
1195
1196 if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
1197 Log("fssync: volume %" AFS_VOLID_FMT " moved to %x; breaking all call backs\n",
1198 afs_printable_VolumeId_lu(vcom->vop->volume), vcom->hdr->reason);
1199 VOL_UNLOCK;
1200 (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1201 VOL_LOCK;
1202 }
1203
1204
1205 done:
1206 return code;
1207 }
1208
1209 /**
1210 * service an FSYNC request to mark a volume as destroyed.
1211 *
1212 * @param[in] vcom pointer command object
1213 * @param[out] res object in which to store response packet
1214 *
1215 * @return operation status
1216 * @retval SYNC_OK volume marked as destroyed
1217 * @retval SYNC_FAILED invalid command protocol message
1218 * @retval SYNC_DENIED current volume state does not permit this operation
1219 *
1220 * @note this is an FSYNC RPC server stub
1221 *
1222 * @note this procedure handles the following FSSYNC command codes:
1223 * - FSYNC_VOL_DONE
1224 *
1225 * @note the supplementary reason code contains additional details. For
1226 * instance, SYNC_OK is still returned when the partition specified
1227 * does not match the one registered in the volume object -- reason
1228 * will be FSYNC_WRONG_PART in this case.
1229 *
1230 * @internal
1231 */
1232 static afs_int32
1233 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1234 {
1235 afs_int32 code = SYNC_FAILED;
1236 Error error;
1237 Volume * vp;
1238
1239 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1240 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1241 goto done;
1242 }
1243
1244 /* don't try to put online, this call is made only after deleting
1245 * a volume, in which case we want to remove the vol # from the
1246 * OfflineVolumes array only */
1247 if (vcom->v)
1248 vcom->v->volumeID = 0;
1249
1250 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1251 if (vp) {
1252 if (FSYNC_partMatch(vcom, vp, 1)) {
1253 #ifdef AFS_DEMAND_ATTACH_FS
1254 VCreateReservation_r(vp);
1255 VWaitExclusiveState_r(vp);
1256
1257 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1258 (V_attachState(vp) == VOL_STATE_PREATTACHED) ||
1259 VIsErrorState(V_attachState(vp))) {
1260
1261 /* Change state to DELETED, not UNATTACHED, so clients get
1262 * a VNOVOL error when they try to access from now on. */
1263
1264 VChangeState_r(vp, VOL_STATE_DELETED);
1265 VDeregisterVolOp_r(vp);
1266
1267 /* Volume is gone; clear out old salvage stats */
1268 memset(&vp->salvage, 0, sizeof(vp->salvage));
1269
1270 /* Someday we should free the vp, too, after about 2 hours,
1271 * possibly by putting the vp back on the VLRU. */
1272
1273 code = SYNC_OK;
1274 } else if (V_attachState(vp) == VOL_STATE_DELETED) {
1275 VDeregisterVolOp_r(vp);
1276 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1277
1278 } else {
1279 code = SYNC_DENIED;
1280 res->hdr.reason = FSYNC_BAD_STATE;
1281 }
1282
1283 VCancelReservation_r(vp);
1284 vp = NULL;
1285 #else /* AFS_DEMAND_ATTACH_FS */
1286 if (!vp->specialStatus) {
1287 vp->specialStatus = VNOVOL;
1288 }
1289 code = SYNC_OK;
1290 #endif /* !AFS_DEMAND_ATTACH_FS */
1291 } else {
1292 code = SYNC_OK; /* XXX is this really a good idea? */
1293 res->hdr.reason = FSYNC_WRONG_PART;
1294 }
1295 } else {
1296 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1297 }
1298
1299 done:
1300 return code;
1301 }
1302
1303 #ifdef AFS_DEMAND_ATTACH_FS
1304 /**
1305 * service an FSYNC request to transition a volume to the hard error state.
1306 *
1307 * @param[in] vcom pointer command object
1308 * @param[out] res object in which to store response packet
1309 *
1310 * @return operation status
1311 * @retval SYNC_OK volume transitioned to hard error state
1312 * @retval SYNC_FAILED invalid command protocol message
1313 * @retval SYNC_DENIED (see note)
1314 *
1315 * @note this is an FSYNC RPC server stub
1316 *
1317 * @note this procedure handles the following FSSYNC command codes:
1318 * - FSYNC_VOL_FORCE_ERROR
1319 *
1320 * @note SYNC_DENIED is returned in the following cases:
1321 * - no partition name is specified (reason field set to
1322 * FSYNC_WRONG_PART).
1323 * - volume id not known to fileserver (reason field set
1324 * to FSYNC_UNKNOWN_VOLID).
1325 *
1326 * @note demand attach fileserver only
1327 *
1328 * @internal
1329 */
1330 static afs_int32
1331 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1332 {
1333 Error error;
1334 Volume * vp;
1335 afs_int32 code = SYNC_FAILED;
1336
1337 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1338 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1339 goto done;
1340 }
1341
1342 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1343
1344 if (!vp && vcom->hdr->reason == FSYNC_SALVAGE) {
1345 /* The requested volume doesn't seem to exist. However, it is possible
1346 * that this is triggered by trying to create or clone a volume that
1347 * was prevented from succeeding by a half-created volume in the way.
1348 * (e.g. we tried to create volume X, but volume X exists except that
1349 * its .vol header was deleted for some reason) So, still try to
1350 * a salvage for that volume ID. */
1351
1352 Log("FSYNC_com_VolError: attempting to schedule salvage for unknown "
1353 "volume %lu part %s\n", afs_printable_uint32_lu(vcom->vop->volume),
1354 vcom->vop->partName);
1355 vp = VPreAttachVolumeById_r(&error, vcom->vop->partName,
1356 vcom->vop->volume);
1357 }
1358
1359 if (vp) {
1360 if (FSYNC_partMatch(vcom, vp, 0)) {
1361 VCreateReservation_r(vp);
1362 VWaitExclusiveState_r(vp);
1363 VDeregisterVolOp_r(vp);
1364
1365 if (vcom->hdr->reason == FSYNC_SALVAGE) {
1366 FSYNC_backgroundSalvage(vp);
1367 } else {
1368 /* null out salvsync control state, as it's no longer relevant */
1369 memset(&vp->salvage, 0, sizeof(vp->salvage));
1370 VChangeState_r(vp, VOL_STATE_ERROR);
1371 }
1372
1373 VCancelReservation_r(vp);
1374 vp = NULL;
1375
1376 code = SYNC_OK;
1377 } else {
1378 res->hdr.reason = FSYNC_WRONG_PART;
1379 }
1380 } else {
1381 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1382 }
1383
1384 done:
1385 return code;
1386 }
1387 #endif /* AFS_DEMAND_ATTACH_FS */
1388
1389 /**
1390 * service an FSYNC request to break all callbacks for this volume.
1391 *
1392 * @param[in] vcom pointer command object
1393 * @param[out] res object in which to store response packet
1394 *
1395 * @return operation status
1396 * @retval SYNC_OK callback breaks scheduled for volume
1397 *
1398 * @note this is an FSYNC RPC server stub
1399 *
1400 * @note this procedure handles the following FSSYNC command codes:
1401 * - FSYNC_VOL_BREAKCBKS
1402 *
1403 * @note demand attach fileserver only
1404 *
1405 * @todo should do partition matching
1406 *
1407 * @internal
1408 */
1409 static afs_int32
1410 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1411 {
1412 /* if the volume is being restored, break all callbacks on it */
1413 if (V_BreakVolumeCallbacks) {
1414 Log("fssync: breaking all call backs for volume %" AFS_VOLID_FMT "\n",
1415 afs_printable_VolumeId_lu(vcom->vop->volume));
1416 VOL_UNLOCK;
1417 (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1418 VOL_LOCK;
1419 }
1420 return SYNC_OK;
1421 }
1422
1423 /**
1424 * service an FSYNC request to return the Volume object.
1425 *
1426 * @param[in] vcom pointer command object
1427 * @param[out] res object in which to store response packet
1428 *
1429 * @return operation status
1430 * @retval SYNC_OK volume object returned to caller
1431 * @retval SYNC_FAILED bad command packet, or failed to locate volume object
1432 *
1433 * @note this is an FSYNC RPC server stub
1434 *
1435 * @note this procedure handles the following FSSYNC command codes:
1436 * - FSYNC_VOL_QUERY
1437 *
1438 * @internal
1439 */
1440 static afs_int32
1441 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1442 {
1443 afs_int32 code = SYNC_FAILED;
1444 Error error;
1445 Volume * vp;
1446
1447 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1448 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1449 goto done;
1450 }
1451
1452 #ifdef AFS_DEMAND_ATTACH_FS
1453 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1454 #else /* !AFS_DEMAND_ATTACH_FS */
1455 vp = VGetVolume_r(&error, vcom->vop->volume);
1456 #endif /* !AFS_DEMAND_ATTACH_FS */
1457
1458 if (vp) {
1459 if (FSYNC_partMatch(vcom, vp, 1)) {
1460 if (res->payload.len >= sizeof(Volume)) {
1461 memcpy(res->payload.buf, vp, sizeof(Volume));
1462 res->hdr.response_len += sizeof(Volume);
1463 code = SYNC_OK;
1464 } else {
1465 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1466 }
1467 } else {
1468 res->hdr.reason = FSYNC_WRONG_PART;
1469 }
1470 #ifndef AFS_DEMAND_ATTACH_FS
1471 VPutVolume_r(vp);
1472 #endif
1473 } else {
1474 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1475 }
1476
1477 done:
1478 return code;
1479 }
1480
1481 /**
1482 * service an FSYNC request to return the Volume header.
1483 *
1484 * @param[in] vcom pointer command object
1485 * @param[out] res object in which to store response packet
1486 *
1487 * @return operation status
1488 * @retval SYNC_OK volume header returned to caller
1489 * @retval SYNC_FAILED bad command packet, or failed to locate volume header
1490 *
1491 * @note this is an FSYNC RPC server stub
1492 *
1493 * @note this procedure handles the following FSSYNC command codes:
1494 * - FSYNC_VOL_QUERY_HDR
1495 *
1496 * @internal
1497 */
1498 static afs_int32
1499 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1500 {
1501 afs_int32 code = SYNC_FAILED;
1502 Error error;
1503 Volume * vp;
1504
1505 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1506 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1507 goto done;
1508 }
1509 if (res->payload.len < sizeof(VolumeDiskData)) {
1510 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1511 goto done;
1512 }
1513
1514 #ifdef AFS_DEMAND_ATTACH_FS
1515 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1516 #else /* !AFS_DEMAND_ATTACH_FS */
1517 vp = VGetVolume_r(&error, vcom->vop->volume);
1518 #endif
1519
1520 if (vp) {
1521 if (FSYNC_partMatch(vcom, vp, 1)) {
1522 #ifdef AFS_DEMAND_ATTACH_FS
1523 if ((vp->header == NULL) ||
1524 !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
1525 !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
1526 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1527 goto cleanup;
1528 }
1529 #else /* !AFS_DEMAND_ATTACH_FS */
1530 if (!vp || !vp->header) {
1531 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1532 goto cleanup;
1533 }
1534 #endif /* !AFS_DEMAND_ATTACH_FS */
1535 } else {
1536 res->hdr.reason = FSYNC_WRONG_PART;
1537 goto cleanup;
1538 }
1539 } else {
1540 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1541 goto done;
1542 }
1543
1544 memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
1545 res->hdr.response_len += sizeof(VolumeDiskData);
1546 code = SYNC_OK;
1547
1548 cleanup:
1549 #ifndef AFS_DEMAND_ATTACH_FS
1550 VPutVolume_r(vp);
1551 #endif
1552
1553 done:
1554 return code;
1555 }
1556
1557 #ifdef AFS_DEMAND_ATTACH_FS
1558 static afs_int32
1559 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1560 {
1561 afs_int32 code = SYNC_OK;
1562 Error error;
1563 Volume * vp;
1564
1565 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1566
1567 if (vp) {
1568 VCreateReservation_r(vp);
1569 VWaitExclusiveState_r(vp);
1570 }
1571
1572 if (vp && vp->pending_vol_op) {
1573 if (!FSYNC_partMatch(vcom, vp, 1)) {
1574 res->hdr.reason = FSYNC_WRONG_PART;
1575 code = SYNC_FAILED;
1576 } else {
1577 opr_Assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
1578 memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
1579 res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
1580 }
1581 } else {
1582 if (!vp || V_attachState(vp) == VOL_STATE_DELETED) {
1583 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1584 } else if (!FSYNC_partMatch(vcom, vp, 1)) {
1585 res->hdr.reason = FSYNC_WRONG_PART;
1586 } else {
1587 res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
1588 }
1589 code = SYNC_FAILED;
1590 }
1591
1592 if (vp) {
1593 VCancelReservation_r(vp);
1594 }
1595 return code;
1596 }
1597
1598 static afs_int32
1599 FSYNC_com_VGQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1600 {
1601 afs_int32 code = SYNC_FAILED;
1602 int rc;
1603 struct DiskPartition64 * dp;
1604
1605 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1606 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1607 goto done;
1608 }
1609
1610 dp = VGetPartition_r(vcom->vop->partName, 0);
1611 if (dp == NULL) {
1612 res->hdr.reason = FSYNC_BAD_PART;
1613 goto done;
1614 }
1615
1616 opr_Assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
1617
1618 rc = VVGCache_query_r(dp, vcom->vop->volume, res->payload.buf);
1619 switch (rc) {
1620 case 0:
1621 res->hdr.response_len += sizeof(FSSYNC_VGQry_response_t);
1622 code = SYNC_OK;
1623 break;
1624 case EAGAIN:
1625 res->hdr.reason = FSYNC_PART_SCANNING;
1626 break;
1627 case ENOENT:
1628 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1629 break;
1630 default:
1631 break;
1632 }
1633
1634 done:
1635 return code;
1636 }
1637
1638 static afs_int32
1639 FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res)
1640 {
1641 afs_int32 code = SYNC_FAILED;
1642 struct DiskPartition64 * dp;
1643 FSSYNC_VGUpdate_command_t * vgucom;
1644 int rc;
1645
1646 if (com->recv_len != (sizeof(com->hdr) + sizeof(*vgucom))) {
1647 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1648 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1649 code = SYNC_COM_ERROR;
1650 goto done;
1651 }
1652
1653 vgucom = com->payload.buf;
1654
1655 ViceLog(125, ("FSYNC_com_VGUpdate: fd %d got command for parent %lu child "
1656 "%lu partName %.16s\n", (int)fd,
1657 afs_printable_uint32_lu(vgucom->parent),
1658 afs_printable_uint32_lu(vgucom->child),
1659 vgucom->partName));
1660
1661 if (SYNC_verifyProtocolString(vgucom->partName, sizeof(vgucom->partName))) {
1662 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1663 goto done;
1664 }
1665
1666 dp = VGetPartition_r(vgucom->partName, 0);
1667 if (dp == NULL) {
1668 res->hdr.reason = FSYNC_BAD_PART;
1669 goto done;
1670 }
1671
1672 switch(com->hdr.command) {
1673 case FSYNC_VG_ADD:
1674 rc = VVGCache_entry_add_r(dp, vgucom->parent, vgucom->child, NULL);
1675 break;
1676
1677 case FSYNC_VG_DEL:
1678 rc = VVGCache_entry_del_r(dp, vgucom->parent, vgucom->child);
1679 break;
1680
1681 default:
1682 Log("FSYNC_com_VGUpdate called improperly\n");
1683 rc = -1;
1684 break;
1685 }
1686
1687 /* EINVAL means the partition VGC doesn't exist at all; not really
1688 * an error */
1689 if (rc == 0 || rc == EINVAL) {
1690 code = SYNC_OK;
1691 }
1692
1693 if (rc == ENOENT) {
1694 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1695 } else {
1696 res->hdr.reason = FSYNC_WHATEVER;
1697 }
1698
1699 done:
1700 return code;
1701 }
1702
1703 static afs_int32
1704 FSYNC_com_VGScan(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1705 {
1706 afs_int32 code = SYNC_FAILED;
1707 struct DiskPartition64 * dp;
1708
1709 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1710 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1711 goto done;
1712 }
1713
1714 dp = VGetPartition_r(vcom->vop->partName, 0);
1715 if (dp == NULL) {
1716 res->hdr.reason = FSYNC_BAD_PART;
1717 goto done;
1718 }
1719
1720 if (VVGCache_scanStart_r(dp) == 0) {
1721 code = SYNC_OK;
1722 }
1723
1724 done:
1725 return code;
1726 }
1727
1728 static afs_int32
1729 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res)
1730 {
1731 afs_int32 code = SYNC_FAILED;
1732
1733 if (VVGCache_scanStart_r(NULL) == 0) {
1734 code = SYNC_OK;
1735 }
1736
1737 return code;
1738 }
1739 #endif /* AFS_DEMAND_ATTACH_FS */
1740
1741 static afs_int32
1742 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res)
1743 {
1744 afs_int32 code = SYNC_OK;
1745 FSSYNC_VnQry_hdr * qry = com->payload.buf;
1746 Volume * vp;
1747 Vnode * vnp;
1748 Error error;
1749
1750 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
1751 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1752 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1753 return SYNC_COM_ERROR;
1754 }
1755
1756 ViceLog(125, ("FSYNC_com_VnQry: fd %d got command for vol %lu vnode %lu "
1757 "uniq %lu spare %lu partName %.16s\n", (int)fd,
1758 afs_printable_uint32_lu(qry->volume),
1759 afs_printable_uint32_lu(qry->vnode),
1760 afs_printable_uint32_lu(qry->unique),
1761 afs_printable_uint32_lu(qry->spare),
1762 qry->partName));
1763
1764 #ifdef AFS_DEMAND_ATTACH_FS
1765 vp = VLookupVolume_r(&error, qry->volume, NULL);
1766 #else /* !AFS_DEMAND_ATTACH_FS */
1767 vp = VGetVolume_r(&error, qry->volume);
1768 #endif /* !AFS_DEMAND_ATTACH_FS */
1769
1770 if (!vp) {
1771 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1772 code = SYNC_FAILED;
1773 goto done;
1774 }
1775
1776 vnp = VLookupVnode(vp, qry->vnode);
1777 if (!vnp) {
1778 res->hdr.reason = FSYNC_UNKNOWN_VNID;
1779 code = SYNC_FAILED;
1780 goto cleanup;
1781 }
1782
1783 if (Vn_class(vnp)->residentSize > res->payload.len) {
1784 res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1785 code = SYNC_FAILED;
1786 goto cleanup;
1787 }
1788
1789 memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1790 res->hdr.response_len += Vn_class(vnp)->residentSize;
1791
1792 cleanup:
1793 #ifndef AFS_DEMAND_ATTACH_FS
1794 VPutVolume_r(vp);
1795 #endif
1796
1797 done:
1798 return code;
1799 }
1800
1801 static afs_int32
1802 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
1803 {
1804 afs_int32 code = SYNC_OK;
1805 FSSYNC_StatsOp_command scom;
1806
1807 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1808 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1809 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1810 return SYNC_COM_ERROR;
1811 }
1812
1813 scom.hdr = &com->hdr;
1814 scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1815 scom.com = com;
1816
1817 ViceLog(125, ("FSYNC_com_StatsOp: fd %d got command for stats: "
1818 "{vlru_generation = %lu, hash_bucket = %lu, partName = "
1819 "%.16s}\n", (int)fd,
1820 afs_printable_uint32_lu(scom.sop->args.vlru_generation),
1821 afs_printable_uint32_lu(scom.sop->args.hash_bucket),
1822 scom.sop->args.partName));
1823
1824 switch (com->hdr.command) {
1825 case FSYNC_VOL_STATS_GENERAL:
1826 code = FSYNC_com_StatsOpGeneral(&scom, res);
1827 break;
1828 #ifdef AFS_DEMAND_ATTACH_FS
1829 /* statistics for the following subsystems are only tracked
1830 * for demand attach fileservers */
1831 case FSYNC_VOL_STATS_VICEP:
1832 code = FSYNC_com_StatsOpViceP(&scom, res);
1833 break;
1834 case FSYNC_VOL_STATS_HASH:
1835 code = FSYNC_com_StatsOpHash(&scom, res);
1836 break;
1837 case FSYNC_VOL_STATS_HDR:
1838 code = FSYNC_com_StatsOpHdr(&scom, res);
1839 break;
1840 case FSYNC_VOL_STATS_VLRU:
1841 code = FSYNC_com_StatsOpVLRU(&scom, res);
1842 break;
1843 #endif /* AFS_DEMAND_ATTACH_FS */
1844 default:
1845 code = SYNC_BAD_COMMAND;
1846 }
1847
1848 return code;
1849 }
1850
1851 static afs_int32
1852 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1853 {
1854 afs_int32 code = SYNC_OK;
1855
1856 memcpy(res->payload.buf, &VStats, sizeof(VStats));
1857 res->hdr.response_len += sizeof(VStats);
1858
1859 return code;
1860 }
1861
1862 #ifdef AFS_DEMAND_ATTACH_FS
1863 static afs_int32
1864 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1865 {
1866 afs_int32 code = SYNC_OK;
1867 struct DiskPartition64 * dp;
1868 struct DiskPartitionStats64 * stats;
1869
1870 if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1871 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1872 code = SYNC_FAILED;
1873 goto done;
1874 }
1875
1876 dp = VGetPartition_r(scom->sop->args.partName, 0);
1877 if (!dp) {
1878 code = SYNC_FAILED;
1879 } else {
1880 stats = (struct DiskPartitionStats64 *) res->payload.buf;
1881 stats->free = dp->free;
1882 stats->totalUsable = dp->totalUsable;
1883 stats->minFree = dp->minFree;
1884 stats->f_files = dp->f_files;
1885 stats->vol_list_len = dp->vol_list.len;
1886
1887 res->hdr.response_len += sizeof(struct DiskPartitionStats64);
1888 }
1889
1890 done:
1891 return code;
1892 }
1893
1894 static afs_int32
1895 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1896 {
1897 afs_int32 code = SYNC_OK;
1898 struct VolumeHashChainStats * stats;
1899 struct VolumeHashChainHead * head;
1900
1901 if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1902 return SYNC_FAILED;
1903 }
1904
1905 head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1906 stats = (struct VolumeHashChainStats *) res->payload.buf;
1907 stats->table_size = VolumeHashTable.Size;
1908 stats->chain_len = head->len;
1909 stats->chain_cacheCheck = head->cacheCheck;
1910 stats->chain_busy = head->busy;
1911 AssignInt64(head->looks, &stats->chain_looks);
1912 AssignInt64(head->gets, &stats->chain_gets);
1913 AssignInt64(head->reorders, &stats->chain_reorders);
1914
1915 res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1916
1917 return code;
1918 }
1919
1920 static afs_int32
1921 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1922 {
1923 afs_int32 code = SYNC_OK;
1924
1925 memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1926 res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1927
1928 return code;
1929 }
1930
1931 static afs_int32
1932 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1933 {
1934 afs_int32 code = SYNC_OK;
1935
1936 code = SYNC_BAD_COMMAND;
1937
1938 return code;
1939 }
1940 #endif /* AFS_DEMAND_ATTACH_FS */
1941
1942 /**
1943 * populate an FSSYNC_VolOp_info object from a command packet object.
1944 *
1945 * @param[in] vcom pointer to command packet
1946 * @param[out] info pointer to info object which will be populated
1947 *
1948 * @note FSSYNC_VolOp_info objects are attached to Volume objects when
1949 * a volume operation is commenced.
1950 *
1951 * @internal
1952 */
1953 static void
1954 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1955 {
1956 memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1957 memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1958 info->vol_op_state = FSSYNC_VolOpPending;
1959 }
1960
1961 /**
1962 * check whether command packet partition name matches volume
1963 * object's partition name.
1964 *
1965 * @param[in] vcom pointer to command packet
1966 * @param[in] vp pointer to volume object
1967 * @param[in] match_anon anon matching control flag (see note below)
1968 *
1969 * @return whether partitions match
1970 * @retval 0 partitions do NOT match
1971 * @retval 1 partitions match
1972 *
1973 * @note if match_anon is non-zero, then this function will return a
1974 * positive match for a zero-length partition string in the
1975 * command packet.
1976 *
1977 * @internal
1978 */
1979 static int
1980 FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
1981 {
1982 return ((match_anon && vcom->vop->partName[0] == 0) ||
1983 (strncmp(vcom->vop->partName, V_partition(vp)->name,
1984 sizeof(vcom->vop->partName)) == 0));
1985 }
1986
1987
1988 static void
1989 FSYNC_Drop(osi_socket fd)
1990 {
1991 struct offlineInfo *p;
1992 int i;
1993 Error error;
1994 #ifndef AFS_DEMAND_ATTACH_FS
1995 char tvolName[VMAXPATHLEN];
1996 #endif
1997
1998 VOL_LOCK;
1999 p = OfflineVolumes[FindHandler(fd)];
2000 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
2001 if (p[i].volumeID) {
2002 Volume *vp;
2003
2004 #ifdef AFS_DEMAND_ATTACH_FS
2005 vp = VPreAttachVolumeById_r(&error, p[i].partName, p[i].volumeID);
2006 if (vp) {
2007 VCreateReservation_r(vp);
2008 VWaitExclusiveState_r(vp);
2009 VDeregisterVolOp_r(vp);
2010 VCancelReservation_r(vp);
2011 }
2012 #else
2013 tvolName[0] = OS_DIRSEPC;
2014 sprintf(&tvolName[1], VFORMAT, afs_printable_VolumeId_lu(p[i].volumeID));
2015 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
2016 V_VOLUPD);
2017 if (vp)
2018 VPutVolume_r(vp);
2019 #endif /* !AFS_DEMAND_ATTACH_FS */
2020 p[i].volumeID = 0;
2021 }
2022 }
2023 VOL_UNLOCK;
2024 RemoveHandler(fd);
2025 rk_closesocket(fd);
2026 AcceptOn();
2027 }
2028
2029 static int AcceptHandler = -1; /* handler id for accept, if turned on */
2030
2031 static void
2032 AcceptOn(void)
2033 {
2034 if (AcceptHandler == -1) {
2035 opr_Verify(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
2036 AcceptHandler = FindHandler(fssync_server_state.fd);
2037 }
2038 }
2039
2040 static void
2041 AcceptOff(void)
2042 {
2043 if (AcceptHandler != -1) {
2044 opr_Verify(RemoveHandler(fssync_server_state.fd));
2045 AcceptHandler = -1;
2046 }
2047 }
2048
2049 /* The multiple FD handling code. */
2050
2051 static osi_socket HandlerFD[MAXHANDLERS];
2052 static void (*HandlerProc[MAXHANDLERS]) (osi_socket);
2053
2054 static void
2055 InitHandler(void)
2056 {
2057 int i;
2058 ObtainWriteLock(&FSYNC_handler_lock);
2059 for (i = 0; i < MAXHANDLERS; i++) {
2060 HandlerFD[i] = OSI_NULLSOCKET;
2061 HandlerProc[i] = 0;
2062 }
2063 ReleaseWriteLock(&FSYNC_handler_lock);
2064 }
2065
2066 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
2067 static void
2068 CallHandler(struct pollfd *fds, int nfds, int mask)
2069 {
2070 int i;
2071 int handler;
2072 ObtainReadLock(&FSYNC_handler_lock);
2073 for (i = 0; i < nfds; i++) {
2074 if (fds[i].revents & mask) {
2075 handler = FindHandler_r(fds[i].fd);
2076 ReleaseReadLock(&FSYNC_handler_lock);
2077 (*HandlerProc[handler]) (fds[i].fd);
2078 ObtainReadLock(&FSYNC_handler_lock);
2079 }
2080 }
2081 ReleaseReadLock(&FSYNC_handler_lock);
2082 }
2083 #else
2084 static void
2085 CallHandler(fd_set * fdsetp)
2086 {
2087 int i;
2088 ObtainReadLock(&FSYNC_handler_lock);
2089 for (i = 0; i < MAXHANDLERS; i++) {
2090 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
2091 ReleaseReadLock(&FSYNC_handler_lock);
2092 (*HandlerProc[i]) (HandlerFD[i]);
2093 ObtainReadLock(&FSYNC_handler_lock);
2094 }
2095 }
2096 ReleaseReadLock(&FSYNC_handler_lock);
2097 }
2098 #endif
2099
2100 static int
2101 AddHandler(osi_socket afd, void (*aproc) (osi_socket))
2102 {
2103 int i;
2104 ObtainWriteLock(&FSYNC_handler_lock);
2105 for (i = 0; i < MAXHANDLERS; i++)
2106 if (HandlerFD[i] == OSI_NULLSOCKET)
2107 break;
2108 if (i >= MAXHANDLERS) {
2109 ReleaseWriteLock(&FSYNC_handler_lock);
2110 return 0;
2111 }
2112 HandlerFD[i] = afd;
2113 HandlerProc[i] = aproc;
2114 ReleaseWriteLock(&FSYNC_handler_lock);
2115 return 1;
2116 }
2117
2118 static int
2119 FindHandler(osi_socket afd)
2120 {
2121 int i;
2122 ObtainReadLock(&FSYNC_handler_lock);
2123 for (i = 0; i < MAXHANDLERS; i++)
2124 if (HandlerFD[i] == afd) {
2125 ReleaseReadLock(&FSYNC_handler_lock);
2126 return i;
2127 }
2128 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
2129 opr_abort();
2130 AFS_UNREACHED(return(-1)); /* satisfy compiler */
2131 }
2132
2133 static int
2134 FindHandler_r(osi_socket afd)
2135 {
2136 int i;
2137 for (i = 0; i < MAXHANDLERS; i++)
2138 if (HandlerFD[i] == afd) {
2139 return i;
2140 }
2141 opr_abort();
2142 AFS_UNREACHED(return(-1)); /* satisfy compiler */
2143 }
2144
2145 static int
2146 RemoveHandler(osi_socket afd)
2147 {
2148 ObtainWriteLock(&FSYNC_handler_lock);
2149 HandlerFD[FindHandler_r(afd)] = OSI_NULLSOCKET;
2150 ReleaseWriteLock(&FSYNC_handler_lock);
2151 return 1;
2152 }
2153
2154 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
2155 static void
2156 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
2157 {
2158 int i;
2159 int fdi = 0;
2160 ObtainReadLock(&FSYNC_handler_lock);
2161 for (i = 0; i < MAXHANDLERS; i++)
2162 if (HandlerFD[i] != OSI_NULLSOCKET) {
2163 opr_Assert(fdi<maxfds);
2164 fds[fdi].fd = HandlerFD[i];
2165 fds[fdi].events = events;
2166 fds[fdi].revents = 0;
2167 fdi++;
2168 }
2169 *nfds = fdi;
2170 ReleaseReadLock(&FSYNC_handler_lock);
2171 }
2172 #else
2173 static void
2174 GetHandler(fd_set * fdsetp, int *maxfdp)
2175 {
2176 int i;
2177 int maxfd = -1;
2178 FD_ZERO(fdsetp);
2179 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
2180 for (i = 0; i < MAXHANDLERS; i++)
2181 if (HandlerFD[i] != OSI_NULLSOCKET) {
2182 FD_SET(HandlerFD[i], fdsetp);
2183 #ifndef AFS_NT40_ENV
2184 /* On Windows the nfds parameter to select() is ignored */
2185 if (maxfd < HandlerFD[i] || maxfd == (int)-1)
2186 maxfd = HandlerFD[i];
2187 #endif /* AFS_NT40_ENV */
2188 }
2189 *maxfdp = maxfd;
2190 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
2191 }
2192 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
2193
2194 #endif /* FSSYNC_BUILD_SERVER */