not-cplusplus-20050530
[openafs.git] / src / vol / volume.c
index 4b67766..7eb8854 100644 (file)
@@ -152,6 +152,7 @@ pthread_mutex_t vol_fsync_mutex;
 pthread_mutex_t vol_trans_mutex;
 pthread_cond_t vol_put_volume_cond;
 pthread_cond_t vol_sleep_cond;
+int vol_attach_threads = 1;
 #endif /* AFS_PTHREAD_ENV */
 
 #ifdef AFS_OSF_ENV
@@ -209,6 +210,20 @@ ffs(x)
 }
 #endif /* !AFS_HAVE_FFS */
 
+#ifdef AFS_PTHREAD_ENV
+#include "rx/rx_queue.h"
+typedef struct diskpartition_queue_t {
+    struct rx_queue queue;
+    struct DiskPartition * diskP;
+} diskpartition_queue_t;
+typedef struct vinitvolumepackage_thread_t {
+    struct rx_queue queue;
+    pthread_cond_t thread_done_cv;
+    int n_threads_complete;
+} vinitvolumepackage_thread_t;
+static void * VInitVolumePackageThread(void * args);
+#endif /* AFS_PTHREAD_ENV */
+
 struct Lock vol_listLock;      /* Lock obtained when listing volumes:  prevents a volume from being missed if the volume is attached during a list volumes */
 
 extern struct Lock FSYNC_handler_lock;
@@ -229,7 +244,8 @@ int VInit;                  /* 0 - uninitialized,
 bit32 VolumeCacheCheck;                /* Incremented everytime a volume goes on line--
                                 * used to stamp volume headers and in-core
                                 * vnodes.  When the volume goes on-line the
-                                * vnode will be invalidated */
+                                * vnode will be invalidated
+                                * access only with VOL_LOCK held */
 
 int VolumeCacheSize = 200, VolumeGets = 0, VolumeReplacements = 0, Vlooks = 0;
 
@@ -284,10 +300,48 @@ VInitVolumePackage(ProgramType pt, int nLargeVnodes, int nSmallVnodes,
        return -1;
 
     if (programType == fileServer) {
-       DIR *dirp;
-       struct dirent *dp;
        struct DiskPartition *diskP;
+#ifdef AFS_PTHREAD_ENV
+       struct vinitvolumepackage_thread_t params;
+       struct diskpartition_queue_t * dpq;
+       int i, len;
+       pthread_t tid;
+       pthread_attr_t attrs;
+
+       assert(pthread_cond_init(&params.thread_done_cv,NULL) == 0);
+       queue_Init(&params);
+       params.n_threads_complete = 0;
+
+       /* create partition work queue */
+       for (len=0, diskP = DiskPartitionList; diskP; diskP = diskP->next, len++) {
+           dpq = (diskpartition_queue_t *) malloc(sizeof(struct diskpartition_queue_t));
+           assert(dpq != NULL);
+           dpq->diskP = diskP;
+           queue_Prepend(&params,dpq);
+       }
+
+       assert(pthread_attr_init(&attrs) == 0);
+       assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
+
+       len = MIN(len, vol_attach_threads);
+       
+       VOL_LOCK;
+       for (i=0; i < len; i++) {
+           assert(pthread_create
+                  (&tid, &attrs, &VInitVolumePackageThread,
+                   &params) == 0);
+       }
+
+       while(params.n_threads_complete < len) {
+           pthread_cond_wait(&params.thread_done_cv,&vol_glock_mutex);
+       }
+       VOL_UNLOCK;
 
+       assert(pthread_cond_destroy(&params.thread_done_cv) == 0);
+
+#else /* AFS_PTHREAD_ENV */
+       DIR *dirp;
+       struct dirent *dp;
 
        /* Attach all the volumes in this partition */
        for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
@@ -319,18 +373,81 @@ VInitVolumePackage(ProgramType pt, int nLargeVnodes, int nSmallVnodes,
            Log("Partition %s: attached %d volumes; %d volumes not attached\n", diskP->name, nAttached, nUnattached);
            closedir(dirp);
        }
+#endif /* AFS_PTHREAD_ENV */
     }
 
     VInit = 2;                 /* Initialized, and all volumes have been attached */
     if (programType == volumeUtility && connect) {
        if (!VConnectFS()) {
            Log("Unable to connect to file server; aborted\n");
+           Lock_Destroy(&FSYNC_handler_lock);
            exit(1);
        }
     }
     return 0;
 }
 
+#ifdef AFS_PTHREAD_ENV
+static void *
+VInitVolumePackageThread(void * args) {
+    int errors = 0;            /* Number of errors while finding vice partitions. */
+
+    DIR *dirp;
+    struct dirent *dp;
+    struct DiskPartition *diskP;
+    struct vinitvolumepackage_thread_t * params;
+    struct diskpartition_queue_t * dpq;
+
+    params = (vinitvolumepackage_thread_t *) args;
+
+
+    VOL_LOCK;
+    /* Attach all the volumes in this partition */
+    while (queue_IsNotEmpty(params)) {
+        int nAttached = 0, nUnattached = 0;
+
+        dpq = queue_First(params,diskpartition_queue_t);
+       queue_Remove(dpq);
+       VOL_UNLOCK;
+       diskP = dpq->diskP;
+       free(dpq);
+
+       Log("Partition %s: attaching volumes\n", diskP->name);
+       dirp = opendir(VPartitionPath(diskP));
+       assert(dirp);
+       while ((dp = readdir(dirp))) {
+           char *p;
+           p = strrchr(dp->d_name, '.');
+           if (p != NULL && strcmp(p, VHDREXT) == 0) {
+               Error error;
+               Volume *vp;
+               vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
+                                        V_VOLUPD);
+               (*(vp ? &nAttached : &nUnattached))++;
+               if (error == VOFFLINE)
+                   Log("Volume %d stays offline (/vice/offline/%s exists)\n", VolumeNumber(dp->d_name), dp->d_name);
+               else if (LogLevel >= 5) {
+                   Log("Partition %s: attached volume %d (%s)\n",
+                       diskP->name, VolumeNumber(dp->d_name),
+                       dp->d_name);
+               }
+               if (vp) {
+                   VPutVolume(vp);
+               }
+           }
+       }
+       Log("Partition %s: attached %d volumes; %d volumes not attached\n", diskP->name, nAttached, nUnattached);
+       closedir(dirp);
+       VOL_LOCK;
+    }
+
+    params->n_threads_complete++;
+    pthread_cond_signal(&params->thread_done_cv);
+    VOL_UNLOCK;
+    return NULL;
+}
+#endif /* AFS_PTHREAD_ENV */
+
 /* This must be called by any volume utility which needs to run while the
    file server is also running.  This is separated from VInitVolumePackage so
    that a utility can fork--and each of the children can independently
@@ -635,7 +752,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
     }
 
     DiskToVolumeHeader(&iheader, &diskHeader);
-    if (programType == volumeUtility && mode != V_SECRETLY) {
+    if (programType == volumeUtility && mode != V_SECRETLY && mode != V_PEEK) {
        if (FSYNC_askfs(iheader.id, partition, FSYNC_NEEDVOLUME, mode)
            == FSYNC_DENIED) {
            Log("VAttachVolume: attach of volume %u apparently denied by file server\n", iheader.id);
@@ -650,7 +767,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
         * takes the volume offline or not.  If the volume isn't
         * offline, we must not return it when we detach the volume,
         * or the server will abort */
-       if (mode == V_READONLY
+       if (mode == V_READONLY || mode == V_PEEK
            || (!VolumeWriteable(vp) && (mode == V_CLONE || mode == V_DUMP)))
            vp->needsPutBack = 0;
        else
@@ -667,7 +784,8 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
      * for all of that to happen, but if it does, probably the right
      * fix is for the server to allow the return of readonly volumes
      * that it doesn't think are really checked out. */
-    if (programType == volumeUtility && vp == NULL && mode != V_SECRETLY) {
+    if (programType == volumeUtility && vp == NULL &&
+       mode != V_SECRETLY && mode != V_PEEK) {
        FSYNC_askfs(iheader.id, partition, FSYNC_ON, 0);
     } else if (programType == fileServer && vp) {
        V_needsCallback(vp) = 0;
@@ -723,6 +841,7 @@ attach2(Error * ec, char *path, register struct VolumeHeader * header,
     register Volume *vp;
 
     VOL_UNLOCK;
+
     vp = (Volume *) calloc(1, sizeof(Volume));
     assert(vp != NULL);
     vp->specialStatus = (byte) (isbusy ? VBUSY : 0);
@@ -735,18 +854,21 @@ attach2(Error * ec, char *path, register struct VolumeHeader * header,
     IH_INIT(vp->diskDataHandle, partp->device, header->parent,
            header->volumeInfo);
     IH_INIT(vp->linkHandle, partp->device, header->parent, header->linkTable);
-    vp->cacheCheck = ++VolumeCacheCheck;
-    /* just in case this ever rolls over */
-    if (!vp->cacheCheck)
-       vp->cacheCheck = ++VolumeCacheCheck;
     vp->shuttingDown = 0;
     vp->goingOffline = 0;
     vp->nUsers = 1;
+
     VOL_LOCK;
+    vp->cacheCheck = ++VolumeCacheCheck;
+    /* just in case this ever rolls over */
+    if (!vp->cacheCheck)
+       vp->cacheCheck = ++VolumeCacheCheck;
     GetVolumeHeader(vp);
     VOL_UNLOCK;
+
     (void)ReadHeader(ec, V_diskDataHandle(vp), (char *)&V_disk(vp),
                     sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
+
     VOL_LOCK;
     if (*ec) {
        Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%u\n", path, *ec);
@@ -1058,7 +1180,7 @@ VGetVolume_r(Error * ec, VolId volumeId)
                    Log("Volume %u: couldn't reread volume header\n",
                        vp->hashid);
                FreeVolume(vp);
-               vp = 0;
+               vp = NULL;
                break;
            }
        }
@@ -1066,7 +1188,7 @@ VGetVolume_r(Error * ec, VolId volumeId)
        if (vp->shuttingDown) {
            V8++;
            *ec = VNOVOL;
-           vp = 0;
+           vp = NULL;
            break;
        }
        if (programType == fileServer) {
@@ -1809,11 +1931,11 @@ GetVolumeHeader(register Volume * vp)
     int old;
     static int everLogged = 0;
 
-    old = (vp->header != 0);   /* old == volume already has a header */
+    old = (vp->header != NULL);        /* old == volume already has a header */
     if (programType != fileServer) {
        if (!vp->header) {
            hd = (struct volHeader *)calloc(1, sizeof(*vp->header));
-           assert(hd != 0);
+           assert(hd != NULL);
            vp->header = hd;
            hd->back = vp;
        }
@@ -1944,3 +2066,4 @@ VPrintCacheStats(void)
     VPrintCacheStats_r();
     VOL_UNLOCK;
 }
+