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
16 /* Clone a volume. Assumes the new volume is already created */
18 #include <afsconfig.h>
19 #include <afs/param.h>
24 #include <sys/types.h>
26 #ifdef AFS_PTHREAD_ENV
28 #else /* AFS_PTHREAD_ENV */
29 #include <afs/assert.h>
30 #endif /* AFS_PTHREAD_ENV */
46 #include <afs/afsint.h>
50 #include <afs/afssyscalls.h>
54 #include "partition.h"
55 #include "viceinode.h"
57 /*@printflike@*/ extern void Log(const char *format, ...);
59 int (*vol_PollProc) () = 0; /* someone must init this */
61 #define ERROR_EXIT(code) {error = code; goto error_exit;}
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.
71 #define CLONE_MAXITEMS 100
73 struct clone_items *next;
75 Inode data[CLONE_MAXITEMS];
79 struct clone_items *first;
80 struct clone_items *last;
87 ci_AddItem(struct clone_head *ah, Inode aino)
89 register struct clone_items *ti;
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));
95 Log("ci_AddItem: malloc failed\n");
99 ti->next = (struct clone_items *)0;
104 /* first dude in the list */
105 ah->first = ah->last = ti;
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.
113 ti->data[ti->nitems++] = aino;
117 /* initialize a clone header */
119 ci_InitHead(struct clone_head *ah)
121 memset(ah, 0, sizeof(*ah));
125 /* apply a function to all dudes in the set */
127 ci_Apply(struct clone_head *ah, int (*aproc) (), char *arock)
129 register struct clone_items *ti;
132 for (ti = ah->first; ti; ti = ti->next) {
133 for (i = 0; i < ti->nitems; i++) {
134 (*aproc) (ti->data[i], arock);
140 /* free all dudes in the list */
142 ci_Destroy(struct clone_head *ah)
144 register struct clone_items *ti, *ni;
146 for (ti = ah->first; ti; ti = ni) {
147 ni = ti->next; /* guard against freeing */
154 IDecProc(Inode adata, struct clone_rock *aparm)
156 IH_DEC(aparm->h, adata, aparm->vol);
162 DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
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;
176 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
177 int ReadWriteOriginal = VolumeWriteable(rwvp);
178 struct DiskPartition *partition = rwvp->partition;
179 Device device = rwvp->device;
181 /* Open the RW volume's index file and seek to beginning */
182 IH_COPY(rwH, rwvp->vnodeIndex[class].handle);
186 rwfile = FDH_FDOPEN(rwFd, ReadWriteOriginal ? "r+" : "r");
189 STREAM_SEEK(rwfile, vcp->diskSize, 0); /* Will fail if no vnodes */
191 /* Open the clone volume's index file and seek to beginning */
192 IH_COPY(clHout, clvp->vnodeIndex[class].handle);
193 clFdOut = IH_OPEN(clHout);
196 clfileout = FDH_FDOPEN(clFdOut, "a");
199 code = STREAM_SEEK(clfileout, vcp->diskSize, 0);
203 /* If recloning, open the new volume's index; this time for
204 * reading. We never read anything that we're simultaneously
205 * writing, so this all works.
208 IH_COPY(clHin, clvp->vnodeIndex[class].handle);
209 clFdIn = IH_OPEN(clHin);
212 clfilein = FDH_FDOPEN(clFdIn, "r");
215 STREAM_SEEK(clfilein, vcp->diskSize, 0); /* Will fail if no vnodes */
218 /* Initialize list of inodes to nuke */
219 ci_InitHead(&decHead);
220 decRock.h = V_linkHandle(rwvp);
221 decRock.vol = V_parentId(rwvp);
223 /* Read each vnode in the old volume's index file */
224 for (offset = vcp->diskSize;
225 STREAM_READ(rwvnode, vcp->diskSize, 1, rwfile) == 1;
226 offset += vcp->diskSize) {
227 dircloned = inodeinced = 0;
229 /* If we are recloning the volume, read the corresponding vnode
230 * from the clone and determine its inode number.
232 if (reclone && !STREAM_EOF(clfilein)
233 && (STREAM_READ(clvnode, vcp->diskSize, 1, clfilein) == 1)) {
234 clinode = VNDISK_GET_INO(clvnode);
239 if (rwvnode->type != vNull) {
240 if (rwvnode->vnodeMagic != vcp->magic)
242 rwinode = VNDISK_GET_INO(rwvnode);
244 /* Increment the inode if not already */
245 if (clinode && (clinode == rwinode)) {
246 clinode = 0; /* already cloned - don't delete later */
247 } else if (rwinode) {
248 if (IH_INC(V_linkHandle(rwvp), rwinode, V_parentId(rwvp)) ==
250 Log("IH_INC failed: %x, %s, %u errno %d\n",
251 V_linkHandle(rwvp), PrintInode(NULL, rwinode),
252 V_parentId(rwvp), errno);
259 /* If a directory, mark vnode in old volume as cloned */
260 if ((rwvnode->type == vDirectory) && ReadWriteOriginal) {
263 * It is my firmly held belief that immediately after
264 * copy-on-write, the two directories can be identical.
265 * If the new copy is changed (presumably, that is the very
266 * next thing that will happen) then the dataVersion will
269 /* NOTE: the dataVersion++ is incredibly important!!!.
270 * This will cause the inode created by the file server
271 * on copy-on-write to be stamped with a dataVersion bigger
272 * than the current one. The salvager will then do the
274 rwvnode->dataVersion++;
277 code = STREAM_SEEK(rwfile, offset, 0);
280 code = STREAM_WRITE(rwvnode, vcp->diskSize, 1, rwfile);
284 code = STREAM_SEEK(rwfile, offset + vcp->diskSize, 0);
288 rwvnode->dataVersion--; /* Really needs to be set to the value in the inode,
289 * for the read-only volume */
294 /* Overwrite the vnode entry in the clone volume */
296 code = STREAM_WRITE(rwvnode, vcp->diskSize, 1, clfileout);
299 /* Couldn't clone, go back and decrement the inode's link count */
301 if (IH_DEC(V_linkHandle(rwvp), rwinode, V_parentId(rwvp)) ==
303 Log("IH_DEC failed: %x, %s, %u errno %d\n",
304 V_linkHandle(rwvp), PrintInode(NULL, rwinode),
305 V_parentId(rwvp), errno);
310 /* And if the directory was marked clone, unmark it */
313 if (STREAM_SEEK(rwfile, offset, 0) != -1)
314 (void)STREAM_WRITE(rwvnode, vcp->diskSize, 1, rwfile);
319 /* Removal of the old cloned inode */
321 ci_AddItem(&decHead, clinode); /* just queue it */
326 if (STREAM_ERROR(clfileout))
329 /* Clean out any junk at end of clone file */
331 STREAM_SEEK(clfilein, offset, 0);
332 while (STREAM_READ(clvnode, vcp->diskSize, 1, clfilein) == 1) {
333 if (clvnode->type != vNull && VNDISK_GET_INO(clvnode) != 0) {
334 ci_AddItem(&decHead, VNDISK_GET_INO(clvnode));
340 /* come here to finish up. If code is non-zero, we've already run into problems,
341 * and shouldn't do the idecs.
345 STREAM_CLOSE(rwfile);
347 STREAM_CLOSE(clfilein);
349 STREAM_CLOSE(clfileout);
365 /* Next, we sync the disk. We have to reopen in case we're truncating,
366 * since we were using stdio above, and don't know when the buffers
367 * would otherwise be flushed. There's no stdio fftruncate call.
369 rwFd = IH_OPEN(clvp->vnodeIndex[class].handle);
375 /* If doing a reclone, we're keeping the clone. We need to
376 * truncate the file to offset bytes.
378 if (reclone && !error) {
379 error = FDH_TRUNC(rwFd, offset);
386 /* Now finally do the idec's. At this point, all potential
387 * references have been cleaned up and sent to the disk
388 * (see above fclose and fsync). No matter what happens, we
389 * no longer need to keep these references around.
391 code = ci_Apply(&decHead, IDecProc, (char *)&decRock);
394 ci_Destroy(&decHead);
400 CloneVolume(Error * rerror, Volume * original, Volume * new, Volume * old)
402 afs_int32 code, error = 0;
406 reclone = ((new == old) ? 1 : 0);
408 code = DoCloneIndex(original, new, vLarge, reclone);
411 code = DoCloneIndex(original, new, vSmall, reclone);
415 code = CopyVolumeHeader(&V_disk(original), &V_disk(new));