kill-uninitialized-variable-warnings-20081026
[openafs.git] / src / vol / clone.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
10 /*
11         System:         VICE-TWO
12         Module:         clone.c
13
14  */
15
16 /* Clone a volume.  Assumes the new volume is already created */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 RCSID
22     ("$Header$");
23
24 #include <sys/types.h>
25 #include <stdio.h>
26 #ifdef AFS_PTHREAD_ENV
27 #include <assert.h>
28 #else /* AFS_PTHREAD_ENV */
29 #include <afs/assert.h>
30 #endif /* AFS_PTHREAD_ENV */
31 #ifdef AFS_NT40_ENV
32 #include <fcntl.h>
33 #include <windows.h>
34 #include <winbase.h>
35 #include <io.h>
36 #include <time.h>
37 #else
38 #include <sys/file.h>
39 #include <sys/time.h>
40 #endif
41 #include <string.h>
42 #include <errno.h>
43 #include <sys/stat.h>
44
45 #include <rx/xdr.h>
46 #include <afs/afsint.h>
47 #include "nfs.h"
48 #include "lwp.h"
49 #include "lock.h"
50 #include <afs/afssyscalls.h>
51 #include "ihandle.h"
52 #include "vnode.h"
53 #include "volume.h"
54 #include "partition.h"
55 #include "viceinode.h"
56
57 /*@printflike@*/ extern void Log(const char *format, ...);
58
59 int (*vol_PollProc) () = 0;     /* someone must init this */
60
61 #define ERROR_EXIT(code) {error = code; goto error_exit;}
62
63 /* parameters for idec call - this could just be an IHandle_t, but leaving
64  * open the possibility of decrementing the special files as well.
65  */
66 struct clone_rock {
67     IHandle_t *h;
68     VolId vol;
69 };
70
71 #define CLONE_MAXITEMS  100
72 struct clone_items {
73     struct clone_items *next;
74     afs_int32 nitems;
75     Inode data[CLONE_MAXITEMS];
76 };
77
78 struct clone_head {
79     struct clone_items *first;
80     struct clone_items *last;
81 };
82
83 void CloneVolume();
84 void CloneVolume_r();
85
86 static int
87 ci_AddItem(struct clone_head *ah, Inode aino)
88 {
89     register struct clone_items *ti;
90
91     /* if no last elt (first call) or last item full, get a new one */
92     if ((!ah->last) || ah->last->nitems >= CLONE_MAXITEMS) {
93         ti = (struct clone_items *)malloc(sizeof(struct clone_items));
94         if (!ti) {
95             Log("ci_AddItem: malloc failed\n");
96             assert(0);
97         }
98         ti->nitems = 0;
99         ti->next = (struct clone_items *)0;
100         if (ah->last) {
101             ah->last->next = ti;
102             ah->last = ti;
103         } else {
104             /* first dude in the list */
105             ah->first = ah->last = ti;
106         }
107     } else
108         ti = ah->last;
109
110     /* now ti points to the end of the list, to a clone_item with room
111      * for at least one more element.  Add it.
112      */
113     ti->data[ti->nitems++] = aino;
114     return 0;
115 }
116
117 /* initialize a clone header */
118 int
119 ci_InitHead(struct clone_head *ah)
120 {
121     memset(ah, 0, sizeof(*ah));
122     return 0;
123 }
124
125 /* apply a function to all dudes in the set */
126 int
127 ci_Apply(struct clone_head *ah, int (*aproc) (), char *arock)
128 {
129     register struct clone_items *ti;
130     register int i;
131
132     for (ti = ah->first; ti; ti = ti->next) {
133         for (i = 0; i < ti->nitems; i++) {
134             (*aproc) (ti->data[i], arock);
135         }
136     }
137     return 0;
138 }
139
140 /* free all dudes in the list */
141 int
142 ci_Destroy(struct clone_head *ah)
143 {
144     register struct clone_items *ti, *ni;
145
146     for (ti = ah->first; ti; ti = ni) {
147         ni = ti->next;          /* guard against freeing */
148         free(ti);
149     }
150     return 0;
151 }
152
153 static int
154 IDecProc(Inode adata, struct clone_rock *aparm)
155 {
156     IH_DEC(aparm->h, adata, aparm->vol);
157     DOPOLL;
158     return 0;
159 }
160
161 afs_int32
162 DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
163 {
164     afs_int32 code, error = 0;
165     FdHandle_t *rwFd = 0, *clFdIn = 0, *clFdOut = 0;
166     StreamHandle_t *rwfile = 0, *clfilein = 0, *clfileout = 0;
167     IHandle_t *rwH = 0, *clHin = 0, *clHout = 0;
168     char buf[SIZEOF_LARGEDISKVNODE], dbuf[SIZEOF_LARGEDISKVNODE];
169     struct VnodeDiskObject *rwvnode = (struct VnodeDiskObject *)buf;
170     struct VnodeDiskObject *clvnode = (struct VnodeDiskObject *)dbuf;
171     Inode rwinode = 0;
172     Inode clinode;
173     struct clone_head decHead;
174     struct clone_rock decRock;
175     afs_int32 offset = 0;
176     afs_int32 dircloned, inodeinced;
177
178     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
179     int ReadWriteOriginal = VolumeWriteable(rwvp);
180     Device device = rwvp->device;
181
182     /* Open the RW volume's index file and seek to beginning */
183     IH_COPY(rwH, rwvp->vnodeIndex[class].handle);
184     rwFd = IH_OPEN(rwH);
185     if (!rwFd)
186         ERROR_EXIT(EIO);
187     rwfile = FDH_FDOPEN(rwFd, ReadWriteOriginal ? "r+" : "r");
188     if (!rwfile)
189         ERROR_EXIT(EIO);
190     STREAM_SEEK(rwfile, vcp->diskSize, 0);      /* Will fail if no vnodes */
191
192     /* Open the clone volume's index file and seek to beginning */
193     IH_COPY(clHout, clvp->vnodeIndex[class].handle);
194     clFdOut = IH_OPEN(clHout);
195     if (!clFdOut)
196         ERROR_EXIT(EIO);
197     clfileout = FDH_FDOPEN(clFdOut, "a");
198     if (!clfileout)
199         ERROR_EXIT(EIO);
200     code = STREAM_SEEK(clfileout, vcp->diskSize, 0);
201     if (code)
202         ERROR_EXIT(EIO);
203
204     /* If recloning, open the new volume's index; this time for
205      * reading. We never read anything that we're simultaneously
206      * writing, so this all works.
207      */
208     if (reclone) {
209         IH_COPY(clHin, clvp->vnodeIndex[class].handle);
210         clFdIn = IH_OPEN(clHin);
211         if (!clFdIn)
212             ERROR_EXIT(EIO);
213         clfilein = FDH_FDOPEN(clFdIn, "r");
214         if (!clfilein)
215             ERROR_EXIT(EIO);
216         STREAM_SEEK(clfilein, vcp->diskSize, 0);        /* Will fail if no vnodes */
217     }
218
219     /* Initialize list of inodes to nuke */
220     ci_InitHead(&decHead);
221     decRock.h = V_linkHandle(rwvp);
222     decRock.vol = V_parentId(rwvp);
223
224     /* Read each vnode in the old volume's index file */
225     for (offset = vcp->diskSize;
226          STREAM_READ(rwvnode, vcp->diskSize, 1, rwfile) == 1;
227          offset += vcp->diskSize) {
228         dircloned = inodeinced = 0;
229
230         /* If we are recloning the volume, read the corresponding vnode
231          * from the clone and determine its inode number.
232          */
233         if (reclone && !STREAM_EOF(clfilein)
234             && (STREAM_READ(clvnode, vcp->diskSize, 1, clfilein) == 1)) {
235             clinode = VNDISK_GET_INO(clvnode);
236         } else {
237             clinode = 0;
238         }
239
240         if (rwvnode->type != vNull) {
241             if (rwvnode->vnodeMagic != vcp->magic)
242                 ERROR_EXIT(-1);
243             rwinode = VNDISK_GET_INO(rwvnode);
244
245             /* Increment the inode if not already */
246             if (clinode && (clinode == rwinode)) {
247                 clinode = 0;    /* already cloned - don't delete later */
248             } else if (rwinode) {
249                 if (IH_INC(V_linkHandle(rwvp), rwinode, V_parentId(rwvp)) ==
250                     -1) {
251                     Log("IH_INC failed: %x, %s, %u errno %d\n",
252                         V_linkHandle(rwvp), PrintInode(NULL, rwinode),
253                         V_parentId(rwvp), errno);
254                     VForceOffline(rwvp);
255                     ERROR_EXIT(EIO);
256                 }
257                 inodeinced = 1;
258             }
259
260             /* If a directory, mark vnode in old volume as cloned */
261             if ((rwvnode->type == vDirectory) && ReadWriteOriginal) {
262 #ifdef DVINC
263                 /* 
264                  * It is my firmly held belief that immediately after
265                  * copy-on-write, the two directories can be identical.
266                  * If the new copy is changed (presumably, that is the very
267                  * next thing that will happen) then the dataVersion will
268                  * get bumped.
269                  */
270                 /* NOTE:  the dataVersion++ is incredibly important!!!.
271                  * This will cause the inode created by the file server
272                  * on copy-on-write to be stamped with a dataVersion bigger
273                  * than the current one.  The salvager will then do the
274                  * right thing */
275                 rwvnode->dataVersion++;
276 #endif /* DVINC */
277                 rwvnode->cloned = 1;
278                 code = STREAM_SEEK(rwfile, offset, 0);
279                 if (code == -1)
280                     goto clonefailed;
281                 code = STREAM_WRITE(rwvnode, vcp->diskSize, 1, rwfile);
282                 if (code != 1)
283                     goto clonefailed;
284                 dircloned = 1;
285                 code = STREAM_SEEK(rwfile, offset + vcp->diskSize, 0);
286                 if (code == -1)
287                     goto clonefailed;
288 #ifdef DVINC
289                 rwvnode->dataVersion--; /* Really needs to be set to the value in the inode,
290                                          * for the read-only volume */
291 #endif /* DVINC */
292             }
293         }
294
295         /* Overwrite the vnode entry in the clone volume */
296         rwvnode->cloned = 0;
297         code = STREAM_WRITE(rwvnode, vcp->diskSize, 1, clfileout);
298         if (code != 1) {
299           clonefailed:
300             /* Couldn't clone, go back and decrement the inode's link count */
301             if (inodeinced) {
302                 if (IH_DEC(V_linkHandle(rwvp), rwinode, V_parentId(rwvp)) ==
303                     -1) {
304                     Log("IH_DEC failed: %x, %s, %u errno %d\n",
305                         V_linkHandle(rwvp), PrintInode(NULL, rwinode),
306                         V_parentId(rwvp), errno);
307                     VForceOffline(rwvp);
308                     ERROR_EXIT(EIO);
309                 }
310             }
311             /* And if the directory was marked clone, unmark it */
312             if (dircloned) {
313                 rwvnode->cloned = 0;
314                 if (STREAM_SEEK(rwfile, offset, 0) != -1)
315                     (void)STREAM_WRITE(rwvnode, vcp->diskSize, 1, rwfile);
316             }
317             ERROR_EXIT(EIO);
318         }
319
320         /* Removal of the old cloned inode */
321         if (clinode) {
322             ci_AddItem(&decHead, clinode);      /* just queue it */
323         }
324
325         DOPOLL;
326     }
327     if (STREAM_ERROR(clfileout))
328         ERROR_EXIT(EIO);
329
330     /* Clean out any junk at end of clone file */
331     if (reclone) {
332         STREAM_SEEK(clfilein, offset, 0);
333         while (STREAM_READ(clvnode, vcp->diskSize, 1, clfilein) == 1) {
334             if (clvnode->type != vNull && VNDISK_GET_INO(clvnode) != 0) {
335                 ci_AddItem(&decHead, VNDISK_GET_INO(clvnode));
336             }
337             DOPOLL;
338         }
339     }
340
341     /* come here to finish up.  If code is non-zero, we've already run into problems,
342      * and shouldn't do the idecs.
343      */
344   error_exit:
345     if (rwfile)
346         STREAM_CLOSE(rwfile);
347     if (clfilein)
348         STREAM_CLOSE(clfilein);
349     if (clfileout)
350         STREAM_CLOSE(clfileout);
351
352     if (rwFd)
353         FDH_CLOSE(rwFd);
354     if (clFdIn)
355         FDH_CLOSE(clFdIn);
356     if (clFdOut)
357         FDH_CLOSE(clFdOut);
358
359     if (rwH)
360         IH_RELEASE(rwH);
361     if (clHout)
362         IH_RELEASE(clHout);
363     if (clHin)
364         IH_RELEASE(clHin);
365
366     /* Next, we sync the disk. We have to reopen in case we're truncating,
367      * since we were using stdio above, and don't know when the buffers
368      * would otherwise be flushed.  There's no stdio fftruncate call.
369      */
370     rwFd = IH_OPEN(clvp->vnodeIndex[class].handle);
371     if (rwFd == NULL) {
372         if (!error)
373             error = EIO;
374     } else {
375         if (reclone) {
376             /* If doing a reclone, we're keeping the clone. We need to
377              * truncate the file to offset bytes.
378              */
379             if (reclone && !error) {
380                 error = FDH_TRUNC(rwFd, offset);
381             }
382         }
383         FDH_SYNC(rwFd);
384         FDH_CLOSE(rwFd);
385     }
386
387     /* Now finally do the idec's.  At this point, all potential
388      * references have been cleaned up and sent to the disk
389      * (see above fclose and fsync). No matter what happens, we
390      * no longer need to keep these references around.
391      */
392     code = ci_Apply(&decHead, IDecProc, (char *)&decRock);
393     if (!error)
394         error = code;
395     ci_Destroy(&decHead);
396
397     return error;
398 }
399
400 void
401 CloneVolume(Error * rerror, Volume * original, Volume * new, Volume * old)
402 {
403     afs_int32 code, error = 0;
404     afs_int32 reclone;
405
406     *rerror = 0;
407     reclone = ((new == old) ? 1 : 0);
408
409     code = DoCloneIndex(original, new, vLarge, reclone);
410     if (code)
411         ERROR_EXIT(code);
412     code = DoCloneIndex(original, new, vSmall, reclone);
413     if (code)
414         ERROR_EXIT(code);
415
416     code = CopyVolumeHeader(&V_disk(original), &V_disk(new));
417     if (code)
418         ERROR_EXIT(code);
419
420   error_exit:
421     *rerror = error;
422 }