/*
* Copyright 2006-2007, Sine Nomine Associates 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
*/
-/*
+/*
* demand attach fs
* online salvager daemon
*/
#include <afsconfig.h>
#include <afs/param.h>
+#include <roken.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#endif /* ITIMER_REAL */
#endif
-#if defined(AFS_AIX_ENV) || defined(AFS_SUN4_ENV)
-#define WCOREDUMP(x) (x & 0200)
+#ifndef WCOREDUMP
+#define WCOREDUMP(x) ((x) & 0200)
#endif
#include <rx/xdr.h>
#include <afs/afsint.h>
-#include <afs/assert.h>
+#include <afs/afs_assert.h>
#if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
#if defined(AFS_VFSINCL_ENV)
#include <sys/vnode.h>
#include "viceinode.h"
#include "salvage.h"
#include "vol-salvage.h"
+#include "common.h"
#ifdef AFS_NT40_ENV
#include <pthread.h>
#endif
#error "online salvager not supported on NT"
#endif /* AFS_NT40_ENV */
-
-/* Forward declarations */
-/*@printflike@*/ void Log(const char *format, ...);
-/*@printflike@*/ void Abort(const char *format, ...);
-
-
/*@+fcnmacros +macrofcndecl@*/
#ifdef O_LARGEFILE
#define afs_fopen fopen64
static void * SalvageChildReaperThread(void *);
static int DoSalvageVolume(struct SalvageQueueNode * node, int slot);
-static void SalvageServer(void);
+static void SalvageServer(int argc, char **argv);
static void SalvageClient(VolumeId vid, char * pname);
static int Reap_Child(char * prog, int * pid, int * status);
static void * SalvageLogScanningThread(void *);
static void ScanLogs(struct rx_queue *log_watch_queue);
+struct cmdline_rock {
+ int argc;
+ char **argv;
+};
+
struct log_cleanup_node {
struct rx_queue q;
int pid;
static int
handleit(struct cmd_syndesc *as, void *arock)
{
- register struct cmd_item *ti;
+ struct cmd_item *ti;
char pname[100], *temp;
afs_int32 seenpart = 0, seenvol = 0, vid = 0;
+ struct cmdline_rock *rock = (struct cmdline_rock *)arock;
#ifdef AFS_SGI_VNODE_GLUE
if (afs_init_kernel_config(-1) < 0) {
vid = atoi(ti->data);
}
+ if (ShowLog) {
+ printf("-showlog does not work with -client\n");
+ exit(-1);
+ }
+
if (!seenpart || !seenvol) {
printf("You must specify '-partition' and '-volumeid' with the '-client' option\n");
exit(-1);
SalvageClient(vid, pname);
} else { /* salvageserver mode */
- SalvageServer();
+ SalvageServer(rock->argc, rock->argv);
}
return (0);
}
pthread_t main_thread;
#endif
-static char commandLine[150];
-
int
main(int argc, char **argv)
{
struct cmd_syndesc *ts;
int err = 0;
-
- int i;
+ struct cmdline_rock arock;
#ifdef AFS_AIX32_ENV
/*
- * The following signal action for AIX is necessary so that in case of a
- * crash (i.e. core is generated) we can include the user's data section
+ * The following signal action for AIX is necessary so that in case of a
+ * crash (i.e. core is generated) we can include the user's data section
* in the core dump. Unfortunately, by default, only a partial core is
* generated which, in many cases, isn't too useful.
*/
exit(2);
}
#ifdef AFS_NT40_ENV
+ /* Default to binary mode for fopen() */
+ _set_fmode(_O_BINARY);
+
main_thread = pthread_self();
if (spawnDatap && spawnDataLen) {
/* This is a child per partition salvager. Don't setup log or
exit(3);
} else {
#endif
- for (commandLine[0] = '\0', i = 0; i < argc; i++) {
- if (i > 0)
- strlcat(commandLine, " ", sizeof(commandLine));
- strlcat(commandLine, argv[i], sizeof(commandLine));
- }
#ifndef AFS_NT40_ENV
if (geteuid() != 0) {
}
#endif
- ts = cmd_CreateSyntax("initcmd", handleit, NULL, "initialize the program");
+ arock.argc = argc;
+ arock.argv = argv;
+
+ ts = cmd_CreateSyntax("initcmd", handleit, &arock, "initialize the program");
cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL,
"Name of partition to salvage");
cmd_AddParm(ts, "-volumeid", CMD_SINGLE, CMD_OPTIONAL,
afs_int32 code;
SYNC_response res;
SALVSYNC_response_hdr sres;
-
- VInitVolumePackage(volumeUtility, 5, 5, DONT_CONNECT_FS, 0);
+ VolumePackageOptions opts;
+
+ VOptDefaults(volumeUtility, &opts);
+ if (VInitVolumePackage2(volumeUtility, &opts)) {
+ /* VInitVolumePackage2 can fail on e.g. partition attachment errors,
+ * but we don't really care, since all we're doing is trying to use
+ * SALVSYNC */
+ fprintf(stderr, "errors encountered initializing volume package, but "
+ "trying to continue anyway\n");
+ }
SALVSYNC_clientInit();
-
+
code = SALVSYNC_SalvageVolume(vid, pname, SALVSYNC_SALVAGE, SALVSYNC_OPERATOR, 0, NULL);
if (code != SYNC_OK) {
goto sync_error;
static int * child_slot;
static void
-SalvageServer(void)
+SalvageServer(int argc, char **argv)
{
int pid, ret;
struct SalvageQueueNode * node;
pthread_t tid;
pthread_attr_t attrs;
int slot;
+ VolumePackageOptions opts;
/* All entries to the log will be appended. Useful if there are
* multiple salvagers appending to the log.
setlinebuf(logFile);
fprintf(logFile, "%s\n", cml_version_number);
- Log("Starting OpenAFS Online Salvage Server %s (%s)\n", SalvageVersion, commandLine);
-
+ LogCommandLine(argc, argv, "Online Salvage Server",
+ SalvageVersion, "Starting OpenAFS", Log);
/* Get and hold a lock for the duration of the salvage to make sure
* that no other salvage runs at the same time. The routine
- * VInitVolumePackage (called below) makes sure that a file server or
+ * VInitVolumePackage2 (called below) makes sure that a file server or
* other volume utilities don't interfere with the salvage.
*/
-
+
/* even demand attach online salvager
* still needs this because we don't want
* a stand-alone salvager to conflict with
* the salvager daemon */
- ObtainSalvageLock();
+ ObtainSharedSalvageLock();
child_slot = (int *) malloc(Parallel * sizeof(int));
- assert(child_slot != NULL);
+ osi_Assert(child_slot != NULL);
memset(child_slot, 0, Parallel * sizeof(int));
-
+
/* initialize things */
- VInitVolumePackage(salvageServer, 5, 5,
- 1, 0);
+ VOptDefaults(salvageServer, &opts);
+ if (VInitVolumePackage2(salvageServer, &opts)) {
+ Log("Shutting down: errors encountered initializing volume package\n");
+ Exit(1);
+ }
DInit(10);
queue_Init(&pending_q);
queue_Init(&log_cleanup_queue);
- assert(pthread_mutex_init(&worker_lock, NULL) == 0);
- assert(pthread_cond_init(&worker_cv, NULL) == 0);
- assert(pthread_cond_init(&log_cleanup_queue.queue_change_cv, NULL) == 0);
- assert(pthread_attr_init(&attrs) == 0);
+ MUTEX_INIT(&worker_lock, "worker", MUTEX_DEFAULT, 0);
+ CV_INIT(&worker_cv, "worker", CV_DEFAULT, 0);
+ CV_INIT(&log_cleanup_queue.queue_change_cv, "queuechange", CV_DEFAULT, 0);
+ osi_Assert(pthread_attr_init(&attrs) == 0);
/* start up the reaper and log cleaner threads */
- assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
- assert(pthread_create(&tid,
- &attrs,
+ osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
+ osi_Assert(pthread_create(&tid,
+ &attrs,
&SalvageChildReaperThread,
NULL) == 0);
- assert(pthread_create(&tid,
- &attrs,
+ osi_Assert(pthread_create(&tid,
+ &attrs,
&SalvageLogCleanupThread,
NULL) == 0);
- assert(pthread_create(&tid,
+ osi_Assert(pthread_create(&tid,
&attrs,
&SalvageLogScanningThread,
NULL) == 0);
/* loop forever serving requests */
while (1) {
node = SALVSYNC_getWork();
- assert(node != NULL);
+ osi_Assert(node != NULL);
Log("dispatching child to salvage volume %u...\n",
node->command.sop.parent);
if (!child_slot[slot])
break;
}
- assert (slot < Parallel);
+ osi_Assert (slot < Parallel);
do_fork:
pid = Fork();
child_slot[slot] = pid;
node->pid = pid;
VOL_UNLOCK;
-
- assert(pthread_mutex_lock(&worker_lock) == 0);
+
+ MUTEX_ENTER(&worker_lock);
current_workers++;
-
+
/* let the reaper thread know another worker was spawned */
- assert(pthread_cond_broadcast(&worker_cv) == 0);
-
+ CV_BROADCAST(&worker_cv);
+
/* if we're overquota, wait for the reaper */
while (current_workers >= Parallel) {
- assert(pthread_cond_wait(&worker_cv, &worker_lock) == 0);
+ CV_WAIT(&worker_cv, &worker_lock);
}
- assert(pthread_mutex_unlock(&worker_lock) == 0);
+ MUTEX_EXIT(&worker_lock);
}
}
}
* another thread may have held the lock on the FILE
* structure when fork was called! */
- afs_snprintf(childLog, sizeof(childLog), "%s.%d",
+ afs_snprintf(childLog, sizeof(childLog), "%s.%d",
AFSDIR_SERVER_SLVGLOG_FILEPATH, getpid());
logFile = afs_fopen(childLog, "a");
Log("salvageServer: invalid volume id specified; salvage aborted\n");
return 1;
}
-
+
partP = VGetPartition(node->command.sop.partName, 0);
if (!partP) {
- Log("salvageServer: Unknown or unmounted partition %s; salvage aborted\n",
+ Log("salvageServer: Unknown or unmounted partition %s; salvage aborted\n",
node->command.sop.partName);
return 1;
}
+ /* obtain a shared salvage lock in the child worker, so if the
+ * salvageserver restarts (and we continue), we will still hold a lock and
+ * prevent standalone salvagers from interfering */
+ ObtainSharedSalvageLock();
+
/* Salvage individual volume; don't notify fs */
SalvageFileSys1(partP, node->command.sop.parent);
int slot, pid, status;
struct log_cleanup_node * cleanup;
- assert(pthread_mutex_lock(&worker_lock) == 0);
+ MUTEX_ENTER(&worker_lock);
/* loop reaping our children */
while (1) {
/* wait() won't block unless we have children, so
* block on the cond var if we're childless */
while (current_workers == 0) {
- assert(pthread_cond_wait(&worker_cv, &worker_lock) == 0);
+ CV_WAIT(&worker_cv, &worker_lock);
}
- assert(pthread_mutex_unlock(&worker_lock) == 0);
+ MUTEX_EXIT(&worker_lock);
cleanup = (struct log_cleanup_node *) malloc(sizeof(struct log_cleanup_node));
if (child_slot[slot] == pid)
break;
}
- assert(slot < Parallel);
+ osi_Assert(slot < Parallel);
child_slot[slot] = 0;
VOL_UNLOCK;
SALVSYNC_doneWorkByPid(pid, status);
- assert(pthread_mutex_lock(&worker_lock) == 0);
+ MUTEX_ENTER(&worker_lock);
if (cleanup) {
cleanup->pid = pid;
queue_Append(&log_cleanup_queue, cleanup);
- assert(pthread_cond_signal(&log_cleanup_queue.queue_change_cv) == 0);
+ CV_SIGNAL(&log_cleanup_queue.queue_change_cv);
}
/* ok, we've reaped a child */
current_workers--;
- assert(pthread_cond_broadcast(&worker_cv) == 0);
+ CV_BROADCAST(&worker_cv);
}
return NULL;
{
struct log_cleanup_node * cleanup;
- assert(pthread_mutex_lock(&worker_lock) == 0);
+ MUTEX_ENTER(&worker_lock);
while (1) {
while (queue_IsEmpty(&log_cleanup_queue)) {
- assert(pthread_cond_wait(&log_cleanup_queue.queue_change_cv, &worker_lock) == 0);
+ CV_WAIT(&log_cleanup_queue.queue_change_cv, &worker_lock);
}
while (queue_IsNotEmpty(&log_cleanup_queue)) {
cleanup = queue_First(&log_cleanup_queue, log_cleanup_node);
queue_Remove(cleanup);
- assert(pthread_mutex_unlock(&worker_lock) == 0);
+ MUTEX_EXIT(&worker_lock);
SalvageLogCleanup(cleanup->pid);
free(cleanup);
- assert(pthread_mutex_lock(&worker_lock) == 0);
- }
+ MUTEX_ENTER(&worker_lock);
+ }
}
- assert(pthread_mutex_unlock(&worker_lock) == 0);
+ MUTEX_EXIT(&worker_lock);
return NULL;
}
char fn[AFSDIR_PATH_MAX];
static char buf[LOG_XFER_BUF_SIZE];
- afs_snprintf(fn, sizeof(fn), "%s.%d",
+ afs_snprintf(fn, sizeof(fn), "%s.%d",
AFSDIR_SERVER_SLVGLOG_FILEPATH, pid);
-
+
pidlog = open(fn, O_RDONLY);
unlink(fn);
prefix_len = strlen(prefix);
dp = opendir(AFSDIR_LOGS_DIR);
- assert(dp);
+ osi_Assert(dp);
while ((dirp = readdir(dp)) != NULL) {
pid_t pid;
{
struct log_cleanup_node *cleanup, *next;
- assert(pthread_mutex_lock(&worker_lock) == 0);
+ MUTEX_ENTER(&worker_lock);
for (queue_Scan(log_watch_queue, cleanup, next, log_cleanup_node)) {
/* if a process is still running, assume it's the salvage process
if (kill(cleanup->pid, 0) < 0 && errno == ESRCH) {
queue_Remove(cleanup);
queue_Append(&log_cleanup_queue, cleanup);
- assert(pthread_cond_signal(&log_cleanup_queue.queue_change_cv) == 0);
+ CV_SIGNAL(&log_cleanup_queue.queue_change_cv);
}
}
- assert(pthread_mutex_unlock(&worker_lock) == 0);
+ MUTEX_EXIT(&worker_lock);
}