DAFS: Maintain viced volume group hierarchy cache
[openafs.git] / src / vol / fssync-client.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,2008 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
19 #ifndef AFS_PTHREAD_ENV
20 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
21
22 /*
23  * stack size increased from 8K because the HP machine seemed to have trouble
24  * with the smaller stack
25  */
26 #define USUAL_STACK_SIZE        (24 * 1024)
27 #endif /* !AFS_PTHREAD_ENV */
28
29 /*
30    fssync-client.c
31    File server synchronization with external volume utilities.
32    client-side implementation
33  */
34
35 #include <afsconfig.h>
36 #include <afs/param.h>
37
38
39 #include <sys/types.h>
40 #include <stdio.h>
41 #ifdef AFS_NT40_ENV
42 #include <winsock2.h>
43 #include <time.h>
44 #else
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <netdb.h>
49 #include <sys/time.h>
50 #endif
51 #include <errno.h>
52 #ifdef AFS_PTHREAD_ENV
53 #include <assert.h>
54 #else /* AFS_PTHREAD_ENV */
55 #include <afs/assert.h>
56 #endif /* AFS_PTHREAD_ENV */
57 #include <signal.h>
58 #include <string.h>
59
60 #include <rx/xdr.h>
61 #include <afs/afsint.h>
62 #include "nfs.h"
63 #include <afs/errors.h>
64 #include "daemon_com.h"
65 #include "fssync.h"
66 #include "lwp.h"
67 #include "lock.h"
68 #include <afs/afssyscalls.h>
69 #include "ihandle.h"
70 #include "vnode.h"
71 #include "volume.h"
72 #include "partition.h"
73
74 #ifdef FSSYNC_BUILD_CLIENT
75
76 /*@printflike@*/ extern void Log(const char *format, ...);
77
78 extern int LogLevel;
79
80 static SYNC_client_state fssync_state = 
81     { -1,                    /* file descriptor */
82       FSSYNC_ENDPOINT_DECL,  /* server endpoint */
83       FSYNC_PROTO_VERSION,   /* protocol version */
84       5,                     /* connect retry limit */
85       120,                   /* hard timeout */
86       "FSSYNC",              /* protocol name string */
87     };
88
89 #ifdef AFS_PTHREAD_ENV
90 static pthread_mutex_t vol_fsync_mutex;
91 static volatile int vol_fsync_mutex_init = 0;
92 #define VFSYNC_LOCK \
93     assert(pthread_mutex_lock(&vol_fsync_mutex) == 0)
94 #define VFSYNC_UNLOCK \
95     assert(pthread_mutex_unlock(&vol_fsync_mutex) == 0)
96 #else
97 #define VFSYNC_LOCK
98 #define VFSYNC_UNLOCK
99 #endif
100
101 int
102 FSYNC_clientInit(void)
103 {
104 #ifdef AFS_PTHREAD_ENV
105     /* this is safe since it gets called with VOL_LOCK held, or before we go multithreaded */
106     if (!vol_fsync_mutex_init) {
107         assert(pthread_mutex_init(&vol_fsync_mutex, NULL) == 0);
108         vol_fsync_mutex_init = 1;
109     }
110 #endif
111     return SYNC_connect(&fssync_state);
112 }
113
114 void
115 FSYNC_clientFinis(void)
116 {
117     SYNC_closeChannel(&fssync_state);
118 }
119
120 int
121 FSYNC_clientChildProcReconnect(void)
122 {
123     return SYNC_reconnect(&fssync_state);
124 }
125
126 /* fsync client interface */
127 afs_int32
128 FSYNC_askfs(SYNC_command * com, SYNC_response * res)
129 {
130     afs_int32 code;
131
132     VFSYNC_LOCK;
133     code = SYNC_ask(&fssync_state, com, res);
134     VFSYNC_UNLOCK;
135
136     switch (code) {
137     case SYNC_OK:
138     case SYNC_FAILED:
139         break;
140     case SYNC_COM_ERROR:
141     case SYNC_BAD_COMMAND:
142         Log("FSYNC_askfs: fatal FSSYNC protocol error; volume management functionality disabled until next fileserver restart\n");
143         break;
144     case SYNC_DENIED:
145         Log("FSYNC_askfs: FSSYNC request denied for reason=%d\n", res->hdr.reason);
146         break;
147     default:
148         Log("FSYNC_askfs: unknown protocol response %d\n", code);
149         break;
150     }
151     return code;
152 }
153
154
155 /**
156  *  FSSYNC volume operations client interface.
157  *
158  * @param[in]    volume     volume id
159  * @param[in]    partName   partition name string
160  * @param[in]    com        FSSYNC command code
161  * @param[in]    reason     FSSYNC reason sub-code
162  * @param[out]   res        response message
163  *
164  * @return operation status
165  *    @retval SYNC_OK  success
166  */
167 afs_int32
168 FSYNC_GenericOp(void * ext_hdr, size_t ext_len,
169               int command, int reason,
170               SYNC_response * res_in)
171 {
172     SYNC_response res_l, *res;
173     SYNC_command com;
174
175     if (res_in) {
176         res = res_in;
177     } else {
178         res = &res_l;
179         res_l.payload.buf = NULL;
180         res_l.payload.len = 0;
181     }
182
183     memset(&com, 0, sizeof(com));
184
185     com.hdr.programType = programType;
186     com.hdr.command = command;
187     com.hdr.reason = reason;
188     com.hdr.command_len = sizeof(com.hdr) + ext_len;
189     com.payload.buf = ext_hdr;
190     com.payload.len = ext_len;
191
192     return FSYNC_askfs(&com, res);
193 }
194
195 afs_int32
196 FSYNC_VolOp(VolumeId volume, char * partition, 
197             int command, int reason,
198             SYNC_response * res)
199 {
200     FSSYNC_VolOp_hdr vcom;
201
202     memset(&vcom, 0, sizeof(vcom));
203
204     vcom.volume = volume;
205     if (partition)
206         strlcpy(vcom.partName, partition, sizeof(vcom.partName));
207
208     return FSYNC_GenericOp(&vcom, sizeof(vcom), command, reason, res);
209 }
210
211 afs_int32
212 FSYNC_StatsOp(FSSYNC_StatsOp_hdr * scom, int command, int reason,
213               SYNC_response * res)
214 {
215     return FSYNC_GenericOp(scom, sizeof(*scom), command, reason, res);
216 }
217
218 /**
219  * query the volume group cache.
220  *
221  * @param[in]  part     vice partition path
222  * @param[in]  volid    volume id
223  * @param[out] qry      query response object
224  * @param[out] res      SYNC response message
225  *
226  * @return operation status
227  *    @retval SYNC_OK success
228  */
229 afs_int32
230 FSYNC_VGCQuery(char * part,
231              VolumeId volid,
232              FSSYNC_VGQry_response_t * qry,
233              SYNC_response *res)
234 {
235     SYNC_response lres;
236
237     if (!res) {
238         res = &lres;
239     }
240
241     res->hdr.response_len = sizeof(res->hdr);
242     res->payload.buf = qry;
243     res->payload.len = sizeof(*qry);
244
245     return FSYNC_VolOp(volid, part, FSYNC_VG_QUERY, 0, res);
246 }
247
248 /**
249  * perform an update operation on the VGC.
250  *
251  * @param[in] parent    rw volume
252  * @param[in] child     volume id to add
253  * @param[in] partition name of vice partition on which this VG resides
254  * @param[in] opcode    FSSYNC VG cache opcode
255  * @param[in] reason    FSSYNC reason code
256  * @param[out] res      SYNC response message
257  *
258  * @return operation status
259  *    @retval SYNC_OK success
260  *
261  * @internal
262  */
263 static afs_int32
264 _FSYNC_VGCUpdate(char * partition,
265                  VolumeId parent,
266                  VolumeId child,
267                  int opcode,
268                  int reason,
269                  SYNC_response *res)
270 {
271     FSSYNC_VGUpdate_command_t vcom;
272
273     memset(&vcom, 0, sizeof(vcom));
274
275     vcom.parent = parent;
276     vcom.child = child;
277     if (partition)
278         strlcpy(vcom.partName, partition, sizeof(vcom.partName));
279
280     return FSYNC_GenericOp(&vcom, sizeof(vcom), opcode, reason, res);
281 }
282
283 /**
284  * Add volume to volume group cache.
285  *
286  * @param[in] parent    rw volume
287  * @param[in] child     volume id to add
288  * @param[in] partition name of vice partition on which this VG resides
289  * @param[in] reason    FSSYNC reason code
290  * @param[out] res      SYNC response message
291  *
292  * @return operation status
293  *    @retval SYNC_OK success
294  */
295 afs_int32
296 FSYNC_VGCAdd(char * partition,
297              VolumeId parent,
298              VolumeId child,
299              int reason,
300              SYNC_response *res)
301 {
302     return _FSYNC_VGCUpdate(partition, parent, child, FSYNC_VG_ADD, reason, res);
303 }
304
305 /**
306  * Delete volume from volume group cache.
307  *
308  * @param[in] parent    rw volume
309  * @param[in] child     volume id to add
310  * @param[in] partition name of vice partition on which this VG resides
311  * @param[in] reason    FSSYNC reason code
312  * @param[out] res      SYNC response message
313  *
314  * @return operation status
315  *    @retval SYNC_OK success
316  */
317 afs_int32
318 FSYNC_VGCDel(char * partition,
319              VolumeId parent,
320              VolumeId child,
321              int reason,
322              SYNC_response *res)
323 {
324     return _FSYNC_VGCUpdate(partition, parent, child, FSYNC_VG_DEL, reason, res);
325 }
326
327 /**
328  * perform an asynchronous volume group scan.
329  *
330  * @param[in] partition   vice partition string
331  * @param[in] reason      FSSYNC reason code
332  *
333  * @note if partition is NULL, all vice partitions will be scanned.
334  *
335  * @return operation status
336  *    @retval SYNC_OK success
337  */
338 afs_int32
339 FSYNC_VGCScan(char * partition, int reason)
340 {
341     int command;
342
343     if (partition == NULL) {
344         command = FSYNC_VG_SCAN_ALL;
345         partition = "";
346     } else {
347         command = FSYNC_VG_SCAN;
348     }
349
350     return FSYNC_VolOp(0, partition, command, reason, NULL);
351 }
352
353 #endif /* FSSYNC_BUILD_CLIENT */