2 * Copyright 2000, International Business Machines Corporation and others.
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
9 * Portions Copyright (c) 2006,2008 Sine Nomine Associates
15 Institution: The Information Technology Center, Carnegie-Mellon University
19 #ifndef AFS_PTHREAD_ENV
20 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
23 * stack size increased from 8K because the HP machine seemed to have trouble
24 * with the smaller stack
26 #define USUAL_STACK_SIZE (24 * 1024)
27 #endif /* !AFS_PTHREAD_ENV */
31 File server synchronization with external volume utilities.
32 client-side implementation
35 #include <afsconfig.h>
36 #include <afs/param.h>
39 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
52 #ifdef AFS_PTHREAD_ENV
54 #else /* AFS_PTHREAD_ENV */
55 #include <afs/assert.h>
56 #endif /* AFS_PTHREAD_ENV */
61 #include <afs/afsint.h>
63 #include <afs/errors.h>
64 #include "daemon_com.h"
68 #include <afs/afssyscalls.h>
72 #include "partition.h"
75 #ifdef FSSYNC_BUILD_CLIENT
79 static SYNC_client_state fssync_state =
80 { -1, /* file descriptor */
81 FSSYNC_ENDPOINT_DECL, /* server endpoint */
82 FSYNC_PROTO_VERSION, /* protocol version */
83 5, /* connect retry limit */
84 120, /* hard timeout */
85 "FSSYNC", /* protocol name string */
88 #ifdef AFS_PTHREAD_ENV
89 static pthread_mutex_t vol_fsync_mutex;
90 static volatile int vol_fsync_mutex_init = 0;
92 assert(pthread_mutex_lock(&vol_fsync_mutex) == 0)
93 #define VFSYNC_UNLOCK \
94 assert(pthread_mutex_unlock(&vol_fsync_mutex) == 0)
101 FSYNC_clientInit(void)
103 #ifdef AFS_PTHREAD_ENV
104 /* this is safe since it gets called with VOL_LOCK held, or before we go multithreaded */
105 if (!vol_fsync_mutex_init) {
106 assert(pthread_mutex_init(&vol_fsync_mutex, NULL) == 0);
107 vol_fsync_mutex_init = 1;
110 return SYNC_connect(&fssync_state);
114 FSYNC_clientFinis(void)
116 SYNC_closeChannel(&fssync_state);
120 FSYNC_clientChildProcReconnect(void)
122 return SYNC_reconnect(&fssync_state);
125 /* fsync client interface */
127 FSYNC_askfs(SYNC_command * com, SYNC_response * res)
132 code = SYNC_ask(&fssync_state, com, res);
140 case SYNC_BAD_COMMAND:
141 Log("FSYNC_askfs: fatal FSSYNC protocol error; volume management functionality disabled until next fileserver restart\n");
144 Log("FSYNC_askfs: FSSYNC request denied for reason=%d\n", res->hdr.reason);
147 Log("FSYNC_askfs: unknown protocol response %d\n", code);
155 * FSSYNC volume operations client interface.
157 * @param[in] volume volume id
158 * @param[in] partName partition name string
159 * @param[in] com FSSYNC command code
160 * @param[in] reason FSSYNC reason sub-code
161 * @param[out] res response message
163 * @return operation status
164 * @retval SYNC_OK success
167 FSYNC_GenericOp(void * ext_hdr, size_t ext_len,
168 int command, int reason,
169 SYNC_response * res_in)
171 SYNC_response res_l, *res;
178 res_l.payload.buf = NULL;
179 res_l.payload.len = 0;
182 memset(&com, 0, sizeof(com));
184 com.hdr.programType = programType;
185 com.hdr.command = command;
186 com.hdr.reason = reason;
187 com.hdr.command_len = sizeof(com.hdr) + ext_len;
188 com.payload.buf = ext_hdr;
189 com.payload.len = ext_len;
191 return FSYNC_askfs(&com, res);
195 FSYNC_VolOp(VolumeId volume, char * partition,
196 int command, int reason,
199 FSSYNC_VolOp_hdr vcom;
201 memset(&vcom, 0, sizeof(vcom));
203 vcom.volume = volume;
205 strlcpy(vcom.partName, partition, sizeof(vcom.partName));
207 return FSYNC_GenericOp(&vcom, sizeof(vcom), command, reason, res);
211 * verify that the fileserver still thinks we have a volume checked out.
213 * In DAFS, a non-fileserver program accesses a volume by checking it out from
214 * the fileserver (FSYNC_VOL_OFF or FSYNC_VOL_NEEDVOLUME), and then locks the
215 * volume. There is a possibility that the fileserver crashes or restarts for
216 * some reason between volume checkout and locking; if this happens, the
217 * fileserver could attach the volume before we had a chance to lock it. This
218 * function serves to detect if this has happened; it must be called after
219 * volume checkout and locking to make sure the fileserver still thinks we
220 * have the volume. (If it doesn't, we should try to check it out again.)
222 * @param[in] volume volume ID
223 * @param[in] partition partition name string
224 * @param[in] command the command that was used to checkout the volume
225 * @param[in] reason the reason code used to checkout the volume
227 * @return operation status
228 * @retval SYNC_OK the fileserver could not have attached the volume since
229 * it was checked out (either it thinks it is still checked
230 * out, or it doesn't know about the volume)
231 * @retval SYNC_DENIED fileserver may have restarted since checkout; checkout
232 * should be reattempted
233 * @retval SYNC_COM_ERROR internal/fatal error
236 FSYNC_VerifyCheckout(VolumeId volume, char * partition,
237 afs_int32 command, afs_int32 reason)
240 FSSYNC_VolOp_info vop;
244 res.hdr.response_len = sizeof(res.hdr);
245 res.payload.buf = &vop;
246 res.payload.len = sizeof(vop);
248 code = FSYNC_VolOp(volume, partition, FSYNC_VOL_QUERY_VOP, FSYNC_WHATEVER, &res);
249 if (code != SYNC_OK) {
250 if (res.hdr.reason == FSYNC_NO_PENDING_VOL_OP) {
251 Log("FSYNC_VerifyCheckout: fileserver claims no vop for vol %lu "
252 "part %s; fileserver may have restarted since checkout\n",
253 afs_printable_uint32_lu(volume), partition);
257 if (res.hdr.reason == FSYNC_UNKNOWN_VOLID) {
258 /* if the fileserver does not know about this volume, there's no
259 * way it could have attached it, so we're fine */
263 Log("FSYNC_VerifyCheckout: FSYNC_VOL_QUERY_VOP failed for vol %lu "
264 "part %s with code %ld reason %ld\n",
265 afs_printable_uint32_lu(volume), partition,
266 afs_printable_int32_ld(code),
267 afs_printable_int32_ld(res.hdr.reason));
268 return SYNC_COM_ERROR;
273 /* Check if the current vol op is us. Checking pid is probably enough, but
274 * be a little bit paranoid. We could also probably check tid, but I'm not
275 * completely confident of its reliability on all platforms (on pthread
276 * envs, we coerce a pthread_t to an afs_int32, which is not guaranteed
277 * to mean anything significant). */
279 if (vop.com.programType == programType && vop.com.pid == pid &&
280 vop.com.command == command && vop.com.reason == reason) {
282 /* looks like the current pending vol op is the same one as the one
283 * with which we checked it out. success. */
287 Log("FSYNC_VerifyCheckout: vop for vol %lu part %s does not match "
288 "expectations (got pt %ld pid %ld cmd %ld reason %ld, but expected "
289 "pt %ld pid %ld cmd %ld reason %ld); fileserver may have restarted "
290 "since checkout\n", afs_printable_uint32_lu(volume), partition,
291 afs_printable_int32_ld(vop.com.programType),
292 afs_printable_int32_ld(vop.com.pid),
293 afs_printable_int32_ld(vop.com.command),
294 afs_printable_int32_ld(vop.com.reason),
295 afs_printable_int32_ld(programType),
296 afs_printable_int32_ld(pid),
297 afs_printable_int32_ld(command),
298 afs_printable_int32_ld(reason));
304 FSYNC_StatsOp(FSSYNC_StatsOp_hdr * scom, int command, int reason,
307 return FSYNC_GenericOp(scom, sizeof(*scom), command, reason, res);
311 * query the volume group cache.
313 * @param[in] part vice partition path
314 * @param[in] volid volume id
315 * @param[out] qry query response object
316 * @param[out] res SYNC response message
318 * @return operation status
319 * @retval SYNC_OK success
322 FSYNC_VGCQuery(char * part,
324 FSSYNC_VGQry_response_t * qry,
333 res->hdr.response_len = sizeof(res->hdr);
334 res->payload.buf = qry;
335 res->payload.len = sizeof(*qry);
337 return FSYNC_VolOp(volid, part, FSYNC_VG_QUERY, 0, res);
341 * perform an update operation on the VGC.
343 * @param[in] parent rw volume
344 * @param[in] child volume id to add
345 * @param[in] partition name of vice partition on which this VG resides
346 * @param[in] opcode FSSYNC VG cache opcode
347 * @param[in] reason FSSYNC reason code
348 * @param[out] res SYNC response message
350 * @return operation status
351 * @retval SYNC_OK success
356 _FSYNC_VGCUpdate(char * partition,
363 FSSYNC_VGUpdate_command_t vcom;
365 memset(&vcom, 0, sizeof(vcom));
367 vcom.parent = parent;
370 strlcpy(vcom.partName, partition, sizeof(vcom.partName));
372 return FSYNC_GenericOp(&vcom, sizeof(vcom), opcode, reason, res);
376 * Add volume to volume group cache.
378 * @param[in] parent rw volume
379 * @param[in] child volume id to add
380 * @param[in] partition name of vice partition on which this VG resides
381 * @param[in] reason FSSYNC reason code
382 * @param[out] res SYNC response message
384 * @return operation status
385 * @retval SYNC_OK success
388 FSYNC_VGCAdd(char * partition,
394 return _FSYNC_VGCUpdate(partition, parent, child, FSYNC_VG_ADD, reason, res);
398 * Delete volume from volume group cache.
400 * @param[in] parent rw volume
401 * @param[in] child volume id to add
402 * @param[in] partition name of vice partition on which this VG resides
403 * @param[in] reason FSSYNC reason code
404 * @param[out] res SYNC response message
406 * @return operation status
407 * @retval SYNC_OK success
410 FSYNC_VGCDel(char * partition,
416 return _FSYNC_VGCUpdate(partition, parent, child, FSYNC_VG_DEL, reason, res);
420 * perform an asynchronous volume group scan.
422 * @param[in] partition vice partition string
423 * @param[in] reason FSSYNC reason code
425 * @note if partition is NULL, all vice partitions will be scanned.
427 * @return operation status
428 * @retval SYNC_OK success
431 FSYNC_VGCScan(char * partition, int reason)
435 if (partition == NULL) {
436 command = FSYNC_VG_SCAN_ALL;
439 command = FSYNC_VG_SCAN;
442 return FSYNC_VolOp(0, partition, command, reason, NULL);
445 #endif /* FSSYNC_BUILD_CLIENT */