vol-lock-fd-type-20090323
[openafs.git] / src / vol / partition.c
index e8032e4..26898ca 100644 (file)
@@ -5,6 +5,9 @@
  * 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
+ *
+ * Portions Copyright (c) 2003 Apple Computer, Inc.
+ * Portions Copyright (c) 2006 Sine Nomine Associates
  */
 
 /*
@@ -22,6 +25,7 @@ RCSID
     ("$Header$");
 
 #include <ctype.h>
+#include <string.h>
 #ifdef AFS_NT40_ENV
 #include <windows.h>
 #include <winbase.h>
@@ -104,14 +108,6 @@ RCSID
 #include <mntent.h>
 #endif
 
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-
 #include <rx/xdr.h>
 #include <afs/afsint.h>
 #include "nfs.h"
@@ -185,7 +181,15 @@ RCSID
 /*@printflike@*/ extern void Log(const char *format, ...);
 
 int aixlow_water = 8;          /* default 8% */
-struct DiskPartition *DiskPartitionList;
+struct DiskPartition64 *DiskPartitionList;
+
+#ifdef AFS_DEMAND_ATTACH_FS
+static struct DiskPartition64 *DiskPartitionTable[VOLMAXPARTS+1];
+
+static struct DiskPartition64 * VLookupPartition_r(char * path);
+static void AddPartitionToTable_r(struct DiskPartition64 *);
+static void DeletePartitionFromTable_r(struct DiskPartition64 *);
+#endif /* AFS_DEMAND_ATTACH_FS */
 
 #ifdef AFS_SGI_XFS_IOPS_ENV
 /* Verify that the on disk XFS inodes on the partition are large enough to
@@ -223,14 +227,22 @@ VerifyXFSInodeSize(char *part, char *fstype)
     }
     return code;
 }
-#endif
+#endif /* AFS_SGI_XFS_IOPS_ENV */
 
+int
+VInitPartitionPackage(void)
+{
+#ifdef AFS_DEMAND_ATTACH_ENV
+    memset(&DiskPartitionTable, 0, sizeof(DiskPartitionTable));
+#endif /* AFS_DEMAND_ATTACH_ENV */
+    return 0;
+}
 
 static void
 VInitPartition_r(char *path, char *devname, Device dev)
 {
-    struct DiskPartition *dp, *op;
-    dp = (struct DiskPartition *)malloc(sizeof(struct DiskPartition));
+    struct DiskPartition64 *dp, *op;
+    dp = (struct DiskPartition64 *)malloc(sizeof(struct DiskPartition64));
     /* Add it to the end, to preserve order when we print statistics */
     for (op = DiskPartitionList; op; op = op->next) {
        if (!op->next)
@@ -243,6 +255,7 @@ VInitPartition_r(char *path, char *devname, Device dev)
     dp->next = 0;
     dp->name = (char *)malloc(strlen(path) + 1);
     strncpy(dp->name, path, strlen(path) + 1);
+    dp->index = volutil_GetPartitionID(path);
 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
     /* Create a lockfile for the partition, of the form /vicepa/Lock/vicepa */
     dp->devName = (char *)malloc(2 * strlen(path) + 6);
@@ -252,13 +265,13 @@ VInitPartition_r(char *path, char *devname, Device dev)
     mkdir(dp->devName, 0700);
     strcat(dp->devName, path);
     close(afs_open(dp->devName, O_RDWR | O_CREAT, 0600));
-    dp->device = volutil_GetPartitionID(path);
+    dp->device = dp->index;
 #else
     dp->devName = (char *)malloc(strlen(devname) + 1);
     strncpy(dp->devName, devname, strlen(devname) + 1);
     dp->device = dev;
 #endif
-    dp->lock_fd = -1;
+    dp->lock_fd = INVALID_FD;
     dp->flags = 0;
     dp->f_files = 1;           /* just a default value */
 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
@@ -266,13 +279,22 @@ VInitPartition_r(char *path, char *devname, Device dev)
        (void)namei_ViceREADME(VPartitionPath(dp));
 #endif
     VSetPartitionDiskUsage_r(dp);
+#ifdef AFS_DEMAND_ATTACH_FS
+    AddPartitionToTable_r(dp);
+    queue_Init(&dp->vol_list.head);
+    assert(pthread_cond_init(&dp->vol_list.cv, NULL) == 0);
+    dp->vol_list.len = 0;
+    dp->vol_list.busy = 0;
+#endif /* AFS_DEMAND_ATTACH_FS */
 }
 
 static void
 VInitPartition(char *path, char *devname, Device dev)
 {
-    VOL_LOCK VInitPartition_r(path, devname, dev);
-VOL_UNLOCK}
+    VOL_LOCK;
+    VInitPartition_r(path, devname, dev);
+    VOL_UNLOCK;
+}
 
 #ifndef AFS_NT40_ENV
 /* VAttachPartitions() finds the vice partitions on this server. Calls
@@ -328,7 +350,7 @@ VCheckPartition(char *part, char *devname)
 
        dirp = opendir(part);
        assert(dirp);
-       while (dp = readdir(dirp)) {
+       while ((dp = readdir(dirp))) {
            if (dp->d_name[0] == 'V') {
                Log("This program is compiled with AFS_NAMEI_ENV, but partition %s seems to contain volumes which don't use the namei-interface; aborting\n", part);
                closedir(dirp);
@@ -342,16 +364,16 @@ VCheckPartition(char *part, char *devname)
        Log("This program is compiled without AFS_NAMEI_ENV, but partition %s seems to contain volumes which use the namei-interface; aborting\n", part);
        return -1;
     }
-#endif /* AFS_NAMEI_ENV */
-#endif
 
 #ifdef AFS_SGI_XFS_IOPS_ENV
     if (VerifyXFSInodeSize(part, status.st_fstype) < 0)
        return -1;
 #endif
+#endif /* AFS_NAMEI_ENV */
+#endif /* !AFS_LINUX20_ENV && !AFS_NT40_ENV */
 
 #if defined(AFS_DUX40_ENV) && !defined(AFS_NAMEI_ENV)
-    if (afs_status.st_ino != ROOTINO) {
+    if (status.st_ino != ROOTINO) {
        Log("%s is not a mounted file system; ignored.\n", part);
        return 0;
     }
@@ -395,7 +417,7 @@ VIsAlwaysAttach(char *part)
  * partitions, in the NAMEI fileserver.
  */
 void
-VAttachPartitions2()
+VAttachPartitions2(void)
 {
 #ifdef AFS_NAMEI_ENV
     DIR *dirp;
@@ -433,10 +455,17 @@ VAttachPartitions(void)
     }
     while (!getmntent(mntfile, &mnt)) {
        /* Ignore non ufs or non read/write partitions */
-       if ((strcmp(mnt.mnt_fstype, "ufs") != 0)
+       /* but allow zfs too if we're in the NAMEI environment */
+       if (
+#ifdef AFS_NAMEI_ENV
+           (((strcmp(mnt.mnt_fstype, "ufs") &&
+               strcmp(mnt.mnt_fstype, "zfs"))))
+#else
+           (strcmp(mnt.mnt_fstype, "ufs") != 0)
+#endif
            || (strncmp(mnt.mnt_mntopts, "ro,ignore", 9) == 0))
            continue;
-
+       
        /* If we're going to always attach this partition, do it later. */
        if (VIsAlwaysAttach(mnt.mnt_mountp))
            continue;
@@ -599,7 +628,7 @@ VAttachPartitions(void)
        exit(-1);
     }
 
-    while (fsent = getfsent()) {
+    while ((fsent = getfsent())) {
        if (strcmp(fsent->fs_type, "rw") != 0)
            continue;
 
@@ -706,7 +735,7 @@ VCheckPartition(char *partName)
 int
 VAttachPartitions(void)
 {
-    struct DiskPartition *partP, *prevP, *nextP;
+    struct DiskPartition64 *partP, *prevP, *nextP;
     struct vpt_iter iter;
     struct vptab entry;
 
@@ -807,7 +836,7 @@ VAttachPartitions(void)
  * is required. The canonical name is still in part->name.
  */
 char *
-VPartitionPath(struct DiskPartition *part)
+VPartitionPath(struct DiskPartition64 *part)
 {
 #ifdef AFS_NT40_ENV
     return part->devName;
@@ -817,30 +846,36 @@ VPartitionPath(struct DiskPartition *part)
 }
 
 /* get partition structure, abortp tells us if we should abort on failure */
-struct DiskPartition *
+struct DiskPartition64 *
 VGetPartition_r(char *name, int abortp)
 {
-    register struct DiskPartition *dp;
+    register struct DiskPartition64 *dp;
+#ifdef AFS_DEMAND_ATTACH_FS
+    dp = VLookupPartition_r(name);
+#else /* AFS_DEMAND_ATTACH_FS */
     for (dp = DiskPartitionList; dp; dp = dp->next) {
        if (strcmp(dp->name, name) == 0)
            break;
     }
+#endif /* AFS_DEMAND_ATTACH_FS */
     if (abortp)
        assert(dp != NULL);
     return dp;
 }
 
-struct DiskPartition *
+struct DiskPartition64 *
 VGetPartition(char *name, int abortp)
 {
-    struct DiskPartition *retVal;
-    VOL_LOCK retVal = VGetPartition_r(name, abortp);
-    VOL_UNLOCK return retVal;
+    struct DiskPartition64 *retVal;
+    VOL_LOCK;
+    retVal = VGetPartition_r(name, abortp);
+    VOL_UNLOCK;
+    return retVal;
 }
 
 #ifdef AFS_NT40_ENV
 void
-VSetPartitionDiskUsage_r(register struct DiskPartition *dp)
+VSetPartitionDiskUsage_r(register struct DiskPartition64 *dp)
 {
     ULARGE_INTEGER free_user, total, free_total;
     int ufree, tot, tfree;
@@ -864,9 +899,10 @@ VSetPartitionDiskUsage_r(register struct DiskPartition *dp)
 
 #else
 void
-VSetPartitionDiskUsage_r(register struct DiskPartition *dp)
+VSetPartitionDiskUsage_r(register struct DiskPartition64 *dp)
 {
-    int fd, totalblks, free, used, availblks, bsize, code;
+    int bsize, code;
+    afs_int64 totalblks, free, used, availblks;
     int reserved;
 #ifdef afs_statvfs
     struct afs_statvfs statbuf;
@@ -929,15 +965,17 @@ VSetPartitionDiskUsage_r(register struct DiskPartition *dp)
 #endif /* AFS_NT40_ENV */
 
 void
-VSetPartitionDiskUsage(register struct DiskPartition *dp)
+VSetPartitionDiskUsage(register struct DiskPartition64 *dp)
 {
-    VOL_LOCK VSetPartitionDiskUsage_r(dp);
-VOL_UNLOCK}
+    VOL_LOCK;
+    VSetPartitionDiskUsage_r(dp);
+    VOL_UNLOCK;
+}
 
 void
 VResetDiskUsage_r(void)
 {
-    struct DiskPartition *dp;
+    struct DiskPartition64 *dp;
     for (dp = DiskPartitionList; dp; dp = dp->next) {
        VSetPartitionDiskUsage_r(dp);
 #ifndef AFS_PTHREAD_ENV
@@ -949,8 +987,10 @@ VResetDiskUsage_r(void)
 void
 VResetDiskUsage(void)
 {
-    VOL_LOCK VResetDiskUsage_r();
-VOL_UNLOCK}
+    VOL_LOCK;
+    VResetDiskUsage_r();
+    VOL_UNLOCK;
+}
 
 void
 VAdjustDiskUsage_r(Error * ec, Volume * vp, afs_sfsize_t blocks,
@@ -986,8 +1026,10 @@ void
 VAdjustDiskUsage(Error * ec, Volume * vp, afs_sfsize_t blocks,
                 afs_sfsize_t checkBlocks)
 {
-    VOL_LOCK VAdjustDiskUsage_r(ec, vp, blocks, checkBlocks);
-VOL_UNLOCK}
+    VOL_LOCK;
+    VAdjustDiskUsage_r(ec, vp, blocks, checkBlocks);
+    VOL_UNLOCK;
+}
 
 int
 VDiskUsage_r(Volume * vp, afs_sfsize_t blocks)
@@ -1013,14 +1055,16 @@ int
 VDiskUsage(Volume * vp, afs_sfsize_t blocks)
 {
     int retVal;
-    VOL_LOCK retVal = VDiskUsage_r(vp, blocks);
-    VOL_UNLOCK return retVal;
+    VOL_LOCK;
+    retVal = VDiskUsage_r(vp, blocks);
+    VOL_UNLOCK;
+    return retVal;
 }
 
 void
 VPrintDiskStats_r(void)
 {
-    struct DiskPartition *dp;
+    struct DiskPartition64 *dp;
     for (dp = DiskPartitionList; dp; dp = dp->next) {
        Log("Partition %s: %d available 1K blocks (minfree=%d), ", dp->name,
            dp->totalUsable, dp->minFree);
@@ -1034,8 +1078,10 @@ VPrintDiskStats_r(void)
 void
 VPrintDiskStats(void)
 {
-    VOL_LOCK VPrintDiskStats_r();
-VOL_UNLOCK}
+    VOL_LOCK;
+    VPrintDiskStats_r();
+    VOL_UNLOCK;
+}
 
 #ifdef AFS_NT40_ENV
 /* Need a separate lock file on NT, since NT only has mandatory file locks. */
@@ -1043,20 +1089,20 @@ VOL_UNLOCK}
 void
 VLockPartition_r(char *name)
 {
-    struct DiskPartition *dp = VGetPartition_r(name, 0);
+    struct DiskPartition64 *dp = VGetPartition_r(name, 0);
     OVERLAPPED lap;
 
     if (!dp)
        return;
-    if (dp->lock_fd == -1) {
+    if (dp->lock_fd == INVALID_FD) {
        char path[64];
        int rc;
        (void)sprintf(path, "%s\\%s", VPartitionPath(dp), LOCKFILE);
        dp->lock_fd =
-           (int)CreateFile(path, GENERIC_WRITE,
+           (FD_t)CreateFile(path, GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                            CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
-       assert(dp->lock_fd != (int)INVALID_HANDLE_VALUE);
+       assert(dp->lock_fd != INVALID_FD);
 
        memset((char *)&lap, 0, sizeof(lap));
        rc = LockFileEx((HANDLE) dp->lock_fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1,
@@ -1068,7 +1114,7 @@ VLockPartition_r(char *name)
 void
 VUnlockPartition_r(char *name)
 {
-    register struct DiskPartition *dp = VGetPartition_r(name, 0);
+    register struct DiskPartition64 *dp = VGetPartition_r(name, 0);
     OVERLAPPED lap;
 
     if (!dp)
@@ -1077,7 +1123,7 @@ VUnlockPartition_r(char *name)
 
     UnlockFileEx((HANDLE) dp->lock_fd, 0, 1, 0, &lap);
     CloseHandle((HANDLE) dp->lock_fd);
-    dp->lock_fd = -1;
+    dp->lock_fd = INVALID_FD;
 }
 #else /* AFS_NT40_ENV */
 
@@ -1091,7 +1137,7 @@ VUnlockPartition_r(char *name)
 void
 VLockPartition_r(char *name)
 {
-    register struct DiskPartition *dp = VGetPartition_r(name, 0);
+    register struct DiskPartition64 *dp = VGetPartition_r(name, 0);
     char *partitionName;
     int retries, code;
     struct timeval pausing;
@@ -1101,6 +1147,9 @@ VLockPartition_r(char *name)
     unsigned int *globalMask;
     int globalMaskIndex;
 #endif /* defined(AFS_HPUX_ENV) */
+#if defined(AFS_DARWIN_ENV)
+    char lockfile[MAXPATHLEN];
+#endif /* defined(AFS_DARWIN_ENV) */
 #ifdef AFS_NAMEI_ENV
 #ifdef AFS_AIX42_ENV
     char LockFileName[MAXPATHLEN + 1];
@@ -1120,6 +1169,10 @@ VLockPartition_r(char *name)
     partitionName = dp->devName;
 #endif
     code = O_RDWR;
+#elif defined(AFS_DARWIN_ENV)
+    strlcpy((partitionName = lockfile), dp->name, sizeof(lockfile));
+    strlcat(lockfile, "/.lock.afs", sizeof(lockfile));
+    code = O_RDONLY | O_CREAT;
 #else
     partitionName = dp->name;
     code = O_RDONLY;
@@ -1187,7 +1240,7 @@ VLockPartition_r(char *name)
 void
 VUnlockPartition_r(char *name)
 {
-    register struct DiskPartition *dp = VGetPartition_r(name, 0);
+    register struct DiskPartition64 *dp = VGetPartition_r(name, 0);
     if (!dp)
        return;                 /* no partition, will fail later */
     close(dp->lock_fd);
@@ -1199,11 +1252,104 @@ VUnlockPartition_r(char *name)
 void
 VLockPartition(char *name)
 {
-    VOL_LOCK VLockPartition_r(name);
-VOL_UNLOCK}
+    VOL_LOCK;
+    VLockPartition_r(name);
+    VOL_UNLOCK;
+}
 
 void
 VUnlockPartition(char *name)
 {
-    VOL_LOCK VUnlockPartition_r(name);
-VOL_UNLOCK}
+    VOL_LOCK;
+    VUnlockPartition_r(name);
+    VOL_UNLOCK;
+}
+
+#ifdef AFS_DEMAND_ATTACH_FS
+
+/* XXX not sure this will work on AFS_NT40_ENV
+ * needs to be tested!
+ */
+
+/**
+ * lookup a disk partition object by its index number.
+ *
+ * @param[in] id      partition index number
+ * @param[in] abortp  see abortp usage note below
+ *
+ * @return disk partition object
+ *   @retval NULL no such disk partition
+ *
+ * @note when abortp is non-zero, lookups which would return
+ *       NULL will result in an assertion failure
+ *
+ * @pre VOL_LOCK must be held
+ *
+ * @internal volume package internal use only
+ */
+
+struct DiskPartition64 * 
+VGetPartitionById_r(afs_int32 id, int abortp)
+{
+    struct DiskPartition64 *dp = NULL;
+
+    if ((id >= 0) && (id <= VOLMAXPARTS)) {
+       dp = DiskPartitionTable[id];
+    }
+
+    if (abortp) {
+       assert(dp != NULL);
+    }
+    return dp;
+}
+
+/**
+ * lookup a disk partition object by its index number.
+ *
+ * @param[in] id      partition index number
+ * @param[in] abortp  see abortp usage note below
+ *
+ * @return disk partition object
+ *   @retval NULL no such disk partition
+ *
+ * @note when abortp is non-zero, lookups which would return
+ *       NULL will result in an assertion failure
+ */
+
+struct DiskPartition64 *
+VGetPartitionById(afs_int32 id, int abortp)
+{
+    struct Diskpartition64 * dp;
+
+    VOL_LOCK;
+    dp = VGetPartitionById_r(id, abortp);
+    VOL_UNLOCK;
+
+    return dp;
+}
+
+static struct DiskPartition64 * 
+VLookupPartition_r(char * path)
+{
+    afs_int32 id = volutil_GetPartitionID(path);
+
+    if (id < 0 || id > VOLMAXPARTS)
+       return NULL;
+
+    return DiskPartitionTable[id];
+}
+
+static void 
+AddPartitionToTable_r(struct DiskPartition64 *dp)
+{
+    assert(dp->index >= 0 && dp->index <= VOLMAXPARTS);
+    DiskPartitionTable[dp->index] = dp;
+}
+
+static void 
+DeletePartitionFromTable_r(struct DiskPartition64 *dp)
+{
+    assert(dp->index >= 0 && dp->index <= VOLMAXPARTS);
+    DiskPartitionTable[dp->index] = NULL;
+}
+#endif /* AFS_DEMAND_ATTACH_FS */