vol: allow clones of readonly volumes
[openafs.git] / src / vol / clone.c
index 8bc995d..b3a3abd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
+#include <roken.h>
 
-#include <sys/types.h>
-#include <stdio.h>
-#ifdef AFS_PTHREAD_ENV
-#include <assert.h>
-#else /* AFS_PTHREAD_ENV */
-#include <afs/assert.h>
-#endif /* AFS_PTHREAD_ENV */
 #ifdef AFS_NT40_ENV
-#include <fcntl.h>
 #include <windows.h>
 #include <winbase.h>
-#include <io.h>
-#include <time.h>
-#else
-#include <sys/file.h>
-#include <sys/time.h>
-#include <unistd.h>
 #endif
-#include <string.h>
-#include <errno.h>
-#include <sys/stat.h>
 
 #include <rx/xdr.h>
 #include <afs/afsint.h>
+#include <afs/afssyscalls.h>
+
 #include "nfs.h"
 #include "lwp.h"
 #include "lock.h"
-#include <afs/afssyscalls.h>
 #include "ihandle.h"
 #include "vnode.h"
 #include "volume.h"
 #include "partition.h"
 #include "viceinode.h"
 #include "vol_prototypes.h"
-
-/*@printflike@*/ extern void Log(const char *format, ...);
+#include "common.h"
 
 int (*vol_PollProc) (void) = 0;        /* someone must init this */
 
-#define ERROR_EXIT(code) {error = code; goto error_exit;}
+#define ERROR_EXIT(code) do { \
+    error = code; \
+    goto error_exit; \
+} while (0)
 
 /* parameters for idec call - this could just be an IHandle_t, but leaving
  * open the possibility of decrementing the special files as well.
@@ -85,14 +72,14 @@ void CloneVolume(Error *, Volume *, Volume *, Volume *);
 static int
 ci_AddItem(struct clone_head *ah, Inode aino)
 {
-    register struct clone_items *ti;
+    struct clone_items *ti;
 
     /* if no last elt (first call) or last item full, get a new one */
     if ((!ah->last) || ah->last->nitems >= CLONE_MAXITEMS) {
        ti = (struct clone_items *)malloc(sizeof(struct clone_items));
        if (!ti) {
            Log("ci_AddItem: malloc failed\n");
-           assert(0);
+           osi_Panic("ci_AddItem: malloc failed\n");
        }
        ti->nitems = 0;
        ti->next = (struct clone_items *)0;
@@ -125,8 +112,8 @@ ci_InitHead(struct clone_head *ah)
 int
 ci_Apply(struct clone_head *ah, int (*aproc) (Inode,  void *), void *arock)
 {
-    register struct clone_items *ti;
-    register int i;
+    struct clone_items *ti;
+    int i;
 
     for (ti = ah->first; ti; ti = ti->next) {
        for (i = 0; i < ti->nitems; i++) {
@@ -140,7 +127,7 @@ ci_Apply(struct clone_head *ah, int (*aproc) (Inode,  void *), void *arock)
 int
 ci_Destroy(struct clone_head *ah)
 {
-    register struct clone_items *ti, *ni;
+    struct clone_items *ti, *ni;
 
     for (ti = ah->first; ti; ti = ni) {
        ni = ti->next;          /* guard against freeing */
@@ -172,11 +159,32 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
     Inode clinode;
     struct clone_head decHead;
     struct clone_rock decRock;
-    afs_int32 offset = 0;
+    afs_foff_t offset = 0;
     afs_int32 dircloned, inodeinced;
+    afs_int32 filecount = 0, diskused = 0;
+    afs_ino_str_t stmp;
 
     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
-    int ReadWriteOriginal = VolumeWriteable(rwvp);
+    /*
+     * The fileserver's -readonly switch should make this false, but we
+     * have no useful way to know in the volserver.
+     * This doesn't make client data mutable.
+     */
+    int ReadWriteOriginal = 1;
+
+    /* Correct number of files in volume: this assumes indexes are always
+       cloned starting with vLarge */
+    if (ReadWriteOriginal && class != vLarge) {
+       filecount = V_filecount(rwvp);
+       diskused = V_diskused(rwvp);
+    }
+
+    /* Initialize list of inodes to nuke - must do this before any calls
+     * to ERROR_EXIT, as the error handler requires an initialised list
+     */
+    ci_InitHead(&decHead);
+    decRock.h = V_linkHandle(rwvp);
+    decRock.vol = V_parentId(rwvp);
 
     /* Open the RW volume's index file and seek to beginning */
     IH_COPY(rwH, rwvp->vnodeIndex[class].handle);
@@ -186,7 +194,7 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
     rwfile = FDH_FDOPEN(rwFd, ReadWriteOriginal ? "r+" : "r");
     if (!rwfile)
        ERROR_EXIT(EIO);
-    STREAM_SEEK(rwfile, vcp->diskSize, 0);     /* Will fail if no vnodes */
+    STREAM_ASEEK(rwfile, vcp->diskSize);       /* Will fail if no vnodes */
 
     /* Open the clone volume's index file and seek to beginning */
     IH_COPY(clHout, clvp->vnodeIndex[class].handle);
@@ -196,7 +204,7 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
     clfileout = FDH_FDOPEN(clFdOut, "a");
     if (!clfileout)
        ERROR_EXIT(EIO);
-    code = STREAM_SEEK(clfileout, vcp->diskSize, 0);
+    code = STREAM_ASEEK(clfileout, vcp->diskSize);
     if (code)
        ERROR_EXIT(EIO);
 
@@ -212,14 +220,9 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
        clfilein = FDH_FDOPEN(clFdIn, "r");
        if (!clfilein)
            ERROR_EXIT(EIO);
-       STREAM_SEEK(clfilein, vcp->diskSize, 0);        /* Will fail if no vnodes */
+       STREAM_ASEEK(clfilein, vcp->diskSize);  /* Will fail if no vnodes */
     }
 
-    /* Initialize list of inodes to nuke */
-    ci_InitHead(&decHead);
-    decRock.h = V_linkHandle(rwvp);
-    decRock.vol = V_parentId(rwvp);
-
     /* Read each vnode in the old volume's index file */
     for (offset = vcp->diskSize;
         STREAM_READ(rwvnode, vcp->diskSize, 1, rwfile) == 1;
@@ -237,9 +240,14 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
        }
 
        if (rwvnode->type != vNull) {
+           afs_fsize_t ll;
+
            if (rwvnode->vnodeMagic != vcp->magic)
                ERROR_EXIT(-1);
            rwinode = VNDISK_GET_INO(rwvnode);
+           filecount++;
+           VNDISK_GET_LEN(ll, rwvnode);
+           diskused += nBlocks(ll);
 
            /* Increment the inode if not already */
            if (clinode && (clinode == rwinode)) {
@@ -247,8 +255,8 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
            } else if (rwinode) {
                if (IH_INC(V_linkHandle(rwvp), rwinode, V_parentId(rwvp)) ==
                    -1) {
-                   Log("IH_INC failed: %x, %s, %u errno %d\n",
-                       V_linkHandle(rwvp), PrintInode(NULL, rwinode),
+                   Log("IH_INC failed: %"AFS_PTR_FMT", %s, %u errno %d\n",
+                       V_linkHandle(rwvp), PrintInode(stmp, rwinode),
                        V_parentId(rwvp), errno);
                    VForceOffline(rwvp);
                    ERROR_EXIT(EIO);
@@ -259,7 +267,7 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
            /* If a directory, mark vnode in old volume as cloned */
            if ((rwvnode->type == vDirectory) && ReadWriteOriginal) {
 #ifdef DVINC
-               /* 
+               /*
                 * It is my firmly held belief that immediately after
                 * copy-on-write, the two directories can be identical.
                 * If the new copy is changed (presumably, that is the very
@@ -274,14 +282,14 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
                rwvnode->dataVersion++;
 #endif /* DVINC */
                rwvnode->cloned = 1;
-               code = STREAM_SEEK(rwfile, offset, 0);
+               code = STREAM_ASEEK(rwfile, offset);
                if (code == -1)
                    goto clonefailed;
                code = STREAM_WRITE(rwvnode, vcp->diskSize, 1, rwfile);
                if (code != 1)
                    goto clonefailed;
                dircloned = 1;
-               code = STREAM_SEEK(rwfile, offset + vcp->diskSize, 0);
+               code = STREAM_ASEEK(rwfile, offset + vcp->diskSize);
                if (code == -1)
                    goto clonefailed;
 #ifdef DVINC
@@ -300,8 +308,8 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
            if (inodeinced) {
                if (IH_DEC(V_linkHandle(rwvp), rwinode, V_parentId(rwvp)) ==
                    -1) {
-                   Log("IH_DEC failed: %x, %s, %u errno %d\n",
-                       V_linkHandle(rwvp), PrintInode(NULL, rwinode),
+                   Log("IH_DEC failed: %"AFS_PTR_FMT", %s, %u errno %d\n",
+                       V_linkHandle(rwvp), PrintInode(stmp, rwinode),
                        V_parentId(rwvp), errno);
                    VForceOffline(rwvp);
                    ERROR_EXIT(EIO);
@@ -310,7 +318,7 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
            /* And if the directory was marked clone, unmark it */
            if (dircloned) {
                rwvnode->cloned = 0;
-               if (STREAM_SEEK(rwfile, offset, 0) != -1)
+               if (STREAM_ASEEK(rwfile, offset) != -1)
                    (void)STREAM_WRITE(rwvnode, vcp->diskSize, 1, rwfile);
            }
            ERROR_EXIT(EIO);
@@ -328,7 +336,7 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
 
     /* Clean out any junk at end of clone file */
     if (reclone) {
-       STREAM_SEEK(clfilein, offset, 0);
+       STREAM_ASEEK(clfilein, offset);
        while (STREAM_READ(clvnode, vcp->diskSize, 1, clfilein) == 1) {
            if (clvnode->type != vNull && VNDISK_GET_INO(clvnode) != 0) {
                ci_AddItem(&decHead, VNDISK_GET_INO(clvnode));
@@ -393,6 +401,10 @@ DoCloneIndex(Volume * rwvp, Volume * clvp, VnodeClass class, int reclone)
        error = code;
     ci_Destroy(&decHead);
 
+    if (ReadWriteOriginal && filecount > 0)
+       V_filecount(rwvp) = filecount;
+    if (ReadWriteOriginal && diskused > 0)
+       V_diskused(rwvp) = diskused;
     return error;
 }
 
@@ -401,6 +413,7 @@ CloneVolume(Error * rerror, Volume * original, Volume * new, Volume * old)
 {
     afs_int32 code, error = 0;
     afs_int32 reclone;
+    afs_int32 filecount = V_filecount(original), diskused = V_diskused(original);
 
     *rerror = 0;
     reclone = ((new == old) ? 1 : 0);
@@ -411,6 +424,9 @@ CloneVolume(Error * rerror, Volume * original, Volume * new, Volume * old)
     code = DoCloneIndex(original, new, vSmall, reclone);
     if (code)
        ERROR_EXIT(code);
+    if (filecount != V_filecount(original) || diskused != V_diskused(original))
+       Log("Clone %u: filecount %d -> %d diskused %d -> %d\n",
+           V_id(original), filecount, V_filecount(original), diskused, V_diskused(original));
 
     code = CopyVolumeHeader(&V_disk(original), &V_disk(new));
     if (code)