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