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