/*
* 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 "lwp.h"
#include <afs/afssyscalls.h>
#include "ihandle.h"
+#include "common.h"
#ifdef AFS_NAMEI_ENV
#ifdef AFS_NT40_ENV
#include "ntops.h"
#endif /* !O_LARGEFILE */
-/*@printflike@*/ extern void Log(const char *format, ...);
-
int aixlow_water = 8; /* default 8% */
struct DiskPartition64 *DiskPartitionList;
#ifdef AFS_DEMAND_ATTACH_FS
+/* file to lock to conceptually "lock" the vol headers on a partition */
+#define AFS_PARTLOCK_FILE ".volheaders.lock"
+#define AFS_VOLUMELOCK_FILE ".volume.lock"
+
static struct DiskPartition64 *DiskPartitionTable[VOLMAXPARTS+1];
static struct DiskPartition64 * VLookupPartition_r(char * path);
VInitPartition_r(char *path, char *devname, Device dev)
{
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) {
assert(pthread_cond_init(&dp->vol_list.cv, NULL) == 0);
dp->vol_list.len = 0;
dp->vol_list.busy = 0;
+ {
+ char lockpath[MAXPATHLEN+1];
+ afs_snprintf(lockpath, MAXPATHLEN, "%s/" AFS_PARTLOCK_FILE, dp->name);
+ lockpath[MAXPATHLEN] = '\0';
+ VLockFileInit(&dp->headerLockFile, lockpath);
+
+ afs_snprintf(lockpath, MAXPATHLEN, "%s/" AFS_VOLUMELOCK_FILE, dp->name);
+ lockpath[MAXPATHLEN] = '\0';
+ VLockFileInit(&dp->volLockFile, lockpath);
+ }
+ VDiskLockInit(&dp->headerLock, &dp->headerLockFile, 1);
#endif /* AFS_DEMAND_ATTACH_FS */
}
* attached (return value 1), or only attached when it is a separately
* mounted partition (return value 0). For non-NAMEI environments, it
* always returns 0.
+ *
+ * *awouldattach will be set to 1 if the given path at least looks like a vice
+ * partition (that is, if we return 0, the only thing preventing this partition
+ * from being attached is the existence of the AlwaysAttach file), or to 0
+ * otherwise. *awouldattach is set regardless of whether or not the partition
+ * should always be attached or not.
*/
static int
-VIsAlwaysAttach(char *part)
+VIsAlwaysAttach(char *part, int *awouldattach)
{
#ifdef AFS_NAMEI_ENV
struct afs_stat st;
char checkfile[256];
int ret;
+#endif /* AFS_NAMEI_ENV */
+ if (awouldattach) {
+ *awouldattach = 0;
+ }
+
+#ifdef AFS_NAMEI_ENV
if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE))
return 0;
+ if (awouldattach) {
+ *awouldattach = 1;
+ }
+
strncpy(checkfile, part, 100);
strcat(checkfile, "/");
strcat(checkfile, VICE_ALWAYSATTACH_FILE);
DIR *dirp;
struct dirent *de;
char pname[32];
+ int wouldattach;
dirp = opendir("/");
while ((de = readdir(dirp))) {
/* Only keep track of "/vicepx" partitions since automounter
* may hose us */
- if (VIsAlwaysAttach(pname))
+ if (VIsAlwaysAttach(pname, &wouldattach)) {
VCheckPartition(pname, "");
+ } else {
+ struct afs_stat st;
+ if (wouldattach && VGetPartition(pname, 0) == NULL &&
+ afs_stat(pname, &st) == 0 && S_ISDIR(st.st_mode)) {
+
+ /* This is a /vicep* dir, and it has not been attached as a
+ * partition. This probably means that this is a /vicep* dir
+ * that is not a separate partition, so just give a notice so
+ * admins are not confused as to why their /vicep* dirs are not
+ * being attached.
+ *
+ * It is possible that the dir _is_ a separate partition and we
+ * failed to attach it earlier, making this message a bit
+ * confusing. But that should be rare, and an error message
+ * about the failure will already be logged right before this,
+ * so it should be clear enough. */
+
+ Log("VAttachPartitions: not attaching %s; either it is not a "
+ "separate partition, or it failed to attach (create the "
+ "file %s/" VICE_ALWAYSATTACH_FILE " to force attachment)\n",
+ pname, pname);
+ }
+ }
}
closedir(dirp);
#endif /* AFS_NAMEI_ENV */
#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))
+ if (VIsAlwaysAttach(mnt.mnt_mountp, NULL))
continue;
+#ifndef AFS_NAMEI_ENV
+ if (hasmntopt(&mnt, "logging") != NULL) {
+ Log("This program is compiled without AFS_NAMEI_ENV, and "
+ "partition %s is mounted with the 'logging' option. "
+ "Using the inode fileserver backend with 'logging' UFS "
+ "partitions causes volume corruption, so please either "
+ "mount the partition without logging, or use the namei "
+ "fileserver backend. Aborting...\n", mnt.mnt_mountp);
+ errors++;
+ }
+#endif /* !AFS_NAMEI_ENV */
+
if (VCheckPartition(mnt.mnt_mountp, mnt.mnt_special) < 0)
errors++;
}
continue;
/* If we're going to always attach this partition, do it later. */
- if (VIsAlwaysAttach(mntent->mnt_dir))
+ if (VIsAlwaysAttach(mntent->mnt_dir, NULL))
continue;
if (VCheckPartition(mntent->mnt_dir, mntent->mnt_fsname) < 0)
* (This function was grabbed from df.c)
*/
int
-getmount(register struct vmount **vmountpp)
+getmount(struct vmount **vmountpp)
{
int size;
- register struct vmount *vm;
+ struct vmount *vm;
int nmounts;
/* set initial size of mntctl buffer to a MAGIC NUMBER */
#endif
/* If we're going to always attach this partition, do it later. */
- if (VIsAlwaysAttach(part))
+ if (VIsAlwaysAttach(part, NULL))
continue;
if (VCheckPartition(part, vmt2dataptr(vmountp, VMT_OBJECT)) < 0)
continue;
/* If we're going to always attach this partition, do it later. */
- if (VIsAlwaysAttach(fsent->fs_file))
+ if (VIsAlwaysAttach(fsent->fs_file, NULL))
continue;
if (VCheckPartition(fsent->fs_file, fsent->fs_spec) < 0)
}
while ((mntent = getmntent(mfd))) {
/* If we're going to always attach this partition, do it later. */
- if (VIsAlwaysAttach(mntent->mnt_dir))
+ if (VIsAlwaysAttach(mntent->mnt_dir, NULL))
continue;
if (VCheckPartition(mntent->mnt_dir, mntent->mnt_fsname) < 0)
struct DiskPartition64 *
VGetPartition_r(char *name, int abortp)
{
- register struct DiskPartition64 *dp;
+ struct DiskPartition64 *dp;
#ifdef AFS_DEMAND_ATTACH_FS
dp = VLookupPartition_r(name);
#else /* AFS_DEMAND_ATTACH_FS */
#ifdef AFS_NT40_ENV
void
-VSetPartitionDiskUsage_r(register struct DiskPartition64 *dp)
+VSetPartitionDiskUsage_r(struct DiskPartition64 *dp)
{
ULARGE_INTEGER free_user, total, free_total;
int ufree, tot, tfree;
#else
void
-VSetPartitionDiskUsage_r(register struct DiskPartition64 *dp)
+VSetPartitionDiskUsage_r(struct DiskPartition64 *dp)
{
int bsize, code;
afs_int64 totalblks, free, used, availblks;
#endif /* AFS_NT40_ENV */
void
-VSetPartitionDiskUsage(register struct DiskPartition64 *dp)
+VSetPartitionDiskUsage(struct DiskPartition64 *dp)
{
VOL_LOCK;
VSetPartitionDiskUsage_r(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);
- if (dp->free < 0)
- Log("overallocated by %d blocks\n", -dp->free);
- else
- Log("%d free blocks\n", dp->free);
+ if (dp->free < 0) {
+ Log("Partition %s: %"AFS_INT64_FMT
+ " available 1K blocks (minfree=%"AFS_INT64_FMT"), "
+ "overallocated by %"AFS_INT64_FMT" blocks\n", dp->name,
+ dp->totalUsable, dp->minFree, -dp->free);
+ } else {
+ Log("Partition %s: %"AFS_INT64_FMT
+ " available 1K blocks (minfree=%"AFS_INT64_FMT"), "
+ "%"AFS_INT64_FMT" free blocks\n", dp->name,
+ dp->totalUsable, dp->minFree, dp->free);
+ }
}
}
CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
assert(dp->lock_fd != INVALID_FD);
- memset((char *)&lap, 0, sizeof(lap));
+ memset(&lap, 0, sizeof(lap));
rc = LockFileEx((HANDLE) dp->lock_fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1,
0, &lap);
assert(rc);
void
VUnlockPartition_r(char *name)
{
- register struct DiskPartition64 *dp = VGetPartition_r(name, 0);
+ struct DiskPartition64 *dp = VGetPartition_r(name, 0);
OVERLAPPED lap;
if (!dp)
return; /* no partition, will fail later */
- memset((char *)&lap, 0, sizeof(lap));
+ memset(&lap, 0, sizeof(lap));
UnlockFileEx((HANDLE) dp->lock_fd, 0, 1, 0, &lap);
CloseHandle((HANDLE) dp->lock_fd);
void
VLockPartition_r(char *name)
{
- register struct DiskPartition64 *dp = VGetPartition_r(name, 0);
+ struct DiskPartition64 *dp = VGetPartition_r(name, 0);
char *partitionName;
int retries, code;
struct timeval pausing;
#endif
for (retries = 25; retries; retries--) {
- dp->lock_fd = afs_open(partitionName, code);
+ if (code & O_CREAT)
+ dp->lock_fd = afs_open(partitionName, code, 0644);
+ else
+ dp->lock_fd = afs_open(partitionName, code);
+
if (dp->lock_fd != -1)
break;
if (errno == ENOENT)
void
VUnlockPartition_r(char *name)
{
- register struct DiskPartition64 *dp = VGetPartition_r(name, 0);
+ struct DiskPartition64 *dp = VGetPartition_r(name, 0);
if (!dp)
return; /* no partition, will fail later */
close(dp->lock_fd);
#ifdef AFS_DEMAND_ATTACH_FS
+/* new-style partition locks; these are only to have some mutual exclusion
+ * between the VGC scanner and volume utilies creating/altering vol headers
+ */
+
+/**
+ * lock a partition's vol headers.
+ *
+ * @param[in] dp the partition to lock
+ * @param[in] locktype READ_LOCK or WRITE_LOCK
+ *
+ * @return operation status
+ * @retval 0 success
+ */
+int
+VPartHeaderLock(struct DiskPartition64 *dp, int locktype)
+{
+ int code;
+
+ /* block on acquiring the lock */
+ int nonblock = 0;
+
+ code = VGetDiskLock(&dp->headerLock, locktype, nonblock);
+ if (code) {
+ Log("VPartHeaderLock: error %d locking partititon %s\n", code,
+ VPartitionPath(dp));
+ }
+ return code;
+}
+
+/**
+ * unlock a partition's vol headers.
+ *
+ * @param[in] dp the partition to unlock
+ * @param[in] locktype READ_LOCK or WRITE_LOCK
+ */
+void
+VPartHeaderUnlock(struct DiskPartition64 *dp, int locktype)
+{
+ VReleaseDiskLock(&dp->headerLock, locktype);
+}
+
/* XXX not sure this will work on AFS_NT40_ENV
* needs to be tested!
*/
* @internal volume package internal use only
*/
-struct DiskPartition64 *
+struct DiskPartition64 *
VGetPartitionById_r(afs_int32 id, int abortp)
{
struct DiskPartition64 *dp = NULL;
return dp;
}
-static struct DiskPartition64 *
+static struct DiskPartition64 *
VLookupPartition_r(char * path)
{
afs_int32 id = volutil_GetPartitionID(path);
return DiskPartitionTable[id];
}
-static void
+static void
AddPartitionToTable_r(struct DiskPartition64 *dp)
{
assert(dp->index >= 0 && dp->index <= VOLMAXPARTS);
}
#if 0
-static void
+static void
DeletePartitionFromTable_r(struct DiskPartition64 *dp)
{
assert(dp->index >= 0 && dp->index <= VOLMAXPARTS);