#include "config.h"
#include <stdlib.h>
+#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#endif
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
#include "e2fsck.h"
extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
}
out:
ctx->flags |= E2F_FLAG_ABORT;
- if (ctx->flags & E2F_FLAG_SETJMP_OK)
+ if (!(ctx->options & E2F_OPT_MULTITHREAD) &&
+ ctx->flags & E2F_FLAG_SETJMP_OK)
longjmp(ctx->abort_loc, 1);
+ if (ctx->logf)
+ fprintf(ctx->logf, "Exit status: %d\n", exit_value);
exit(exit_value);
}
+#ifdef HAVE_PTHREAD
+static void thread_log_out(struct e2fsck_thread *tinfo)
+{
+ printf("[Thread %d] %s", tinfo->et_thread_index,
+ tinfo->et_log_buf);
+ tinfo->et_log_length = 0;
+ tinfo->et_log_buf[0] = '\0';
+}
+#endif
+
void log_out(e2fsck_t ctx, const char *fmt, ...)
{
va_list pvar;
+ struct e2fsck_thread *tinfo;
+ int buf_size;
+ int msg_size;
+ int left_size;
+ int fmt_length = strlen(fmt);
+
+#ifdef HAVE_PTHREAD
+ if ((ctx->options & E2F_OPT_MULTITHREAD) && ctx->global_ctx) {
+ tinfo = &ctx->thread_info;
+ buf_size = sizeof(tinfo->et_log_buf);
+ left_size = buf_size - tinfo->et_log_length;
+
+ va_start(pvar, fmt);
+ msg_size = vsnprintf(tinfo->et_log_buf + tinfo->et_log_length,
+ left_size, fmt, pvar);
+ va_end(pvar);
+
+ if (msg_size >= left_size) {
+ tinfo->et_log_buf[tinfo->et_log_length] = '\0';
+
+ assert(msg_size < buf_size);
+ if (msg_size < buf_size) {
+ thread_log_out(tinfo);
+
+ va_start(pvar, fmt);
+ msg_size = vsnprintf(tinfo->et_log_buf, buf_size,
+ fmt, pvar);
+ va_end(pvar);
+
+ tinfo->et_log_length += msg_size;
+ tinfo->et_log_buf[tinfo->et_log_length] = '\0';
+ }
+ } else {
+ tinfo->et_log_length += msg_size;
+ tinfo->et_log_buf[tinfo->et_log_length] = '\0';
+ }
+
+ if (tinfo->et_log_length > 0 &&
+ tinfo->et_log_buf[tinfo->et_log_length - 1] == '\n')
+ thread_log_out(tinfo);
+ } else
+#endif
+ {
+ va_start(pvar, fmt);
+ vprintf(fmt, pvar);
+ va_end(pvar);
+ }
- va_start(pvar, fmt);
- vprintf(fmt, pvar);
- va_end(pvar);
if (ctx->logf) {
va_start(pvar, fmt);
vfprintf(ctx->logf, fmt, pvar);
}
}
-void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
+void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size,
const char *description)
{
void *ret;
char buf[256];
#ifdef DEBUG_ALLOCATE_MEMORY
- printf("Allocating %u bytes for %s...\n", size, description);
+ printf("Allocating %lu bytes for %s...\n", size, description);
#endif
- ret = malloc(size);
- if (!ret) {
- sprintf(buf, "Can't allocate %u bytes for %s\n",
+ if (ext2fs_get_memzero(size, &ret)) {
+ sprintf(buf, "Can't allocate %lu bytes for %s\n",
size, description);
fatal_error(ctx, buf);
}
- memset(ret, 0, size);
+
return ret;
}
char *string_copy(e2fsck_t ctx EXT2FS_ATTR((unused)),
- const char *str, int len)
+ const char *str, size_t len)
{
char *ret;
const char *short_yes = _("yY");
const char *short_no = _("nN");
const char *short_yesall = _("aA");
+ const char *english_yes = "yY";
+ const char *english_no = "nN";
+ const char *english_yesall = "aA";
const char *yesall_prompt = _(" ('a' enables 'yes' to all) ");
const char *extra_prompt = "";
static int yes_answers;
#ifdef HAVE_TERMIOS_H
struct termios termios, tmp;
- tcgetattr (0, &termios);
+ if (tcgetattr (0, &termios) < 0)
+ memset(&termios, 0, sizeof(termios));
tmp = termios;
tmp.c_lflag &= ~(ICANON | ECHO);
tmp.c_cc[VMIN] = 1;
return 0;
}
if (strchr(short_yes, (char) c)) {
+ do_yes:
def = 1;
if (yes_answers >= 0)
yes_answers++;
break;
} else if (strchr(short_no, (char) c)) {
+ do_no:
def = 0;
yes_answers = -1;
break;
} else if (strchr(short_yesall, (char)c)) {
+ do_all:
def = 2;
yes_answers = -1;
ctx->options |= E2F_OPT_YES;
break;
+ } else if (strchr(english_yes, (char) c)) {
+ goto do_yes;
+ } else if (strchr(english_no, (char) c)) {
+ goto do_no;
+ } else if (strchr(english_yesall, (char) c)) {
+ goto do_all;
} else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) {
yes_answers = -1;
break;
#ifdef HAVE_GETRUSAGE
struct rusage r;
#endif
-#ifdef HAVE_MALLINFO
- struct mallinfo malloc_info;
-#endif
struct timeval time_end;
if ((desc && !(ctx->options & E2F_OPT_TIME2)) ||
if (desc)
log_out(ctx, "%s: ", desc);
-#ifdef HAVE_MALLINFO
-#define kbytes(x) (((unsigned long)(x) + 1023) / 1024)
-
- malloc_info = mallinfo();
- log_out(ctx, _("Memory used: %luk/%luk (%luk/%luk), "),
- kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
- kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
-#else
- log_out(ctx, _("Memory used: %lu, "),
- (unsigned long) (((char *) sbrk(0)) -
- ((char *) track->brk_start)));
+#define kbytes(x) (((unsigned long long)(x) + 1023) / 1024)
+#ifdef HAVE_MALLINFO2
+ if (1) {
+ struct mallinfo2 malloc_info = mallinfo2();
+
+ log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
+ kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
+ kbytes(malloc_info.uordblks),
+ kbytes(malloc_info.fordblks));
+ } else
+#elif defined HAVE_MALLINFO
+ /* don't use mallinfo() if over 2GB used, since it returns "int" */
+ if ((char *)sbrk(0) - (char *)track->brk_start < 2LL << 30) {
+ struct mallinfo malloc_info = mallinfo();
+
+ log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
+ kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
+ kbytes(malloc_info.uordblks),
+ kbytes(malloc_info.fordblks));
+ } else
#endif
+ log_out(ctx, _("Memory used: %lluk, "),
+ kbytes(((char *)sbrk(0)) - ((char *)track->brk_start)));
+
#ifdef HAVE_GETRUSAGE
getrusage(RUSAGE_SELF, &r);
}
}
+#ifdef HAVE_PTHREAD
+#define e2fsck_get_lock_context(ctx) \
+ e2fsck_t global_ctx = ctx->global_ctx; \
+ if (!global_ctx) \
+ global_ctx = ctx; \
+
+/**
+ * before we hold write lock, read lock should
+ * has been held.
+ */
+void e2fsck_pass1_fix_lock(e2fsck_t ctx)
+{
+ int err;
+
+ if (!ctx->fs_need_locking)
+ return;
+
+ e2fsck_get_lock_context(ctx);
+ err = pthread_rwlock_trywrlock(&global_ctx->fs_fix_rwlock);
+ assert(err != 0);
+ pthread_rwlock_unlock(&global_ctx->fs_fix_rwlock);
+ pthread_rwlock_wrlock(&global_ctx->fs_fix_rwlock);
+}
+
+void e2fsck_pass1_fix_unlock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ /* unlock write lock */
+ pthread_rwlock_unlock(&global_ctx->fs_fix_rwlock);
+ /* get read lock again */
+ pthread_rwlock_rdlock(&global_ctx->fs_fix_rwlock);
+}
+
+void e2fsck_pass1_check_lock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ pthread_rwlock_rdlock(&global_ctx->fs_fix_rwlock);
+}
+
+void e2fsck_pass1_check_unlock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ pthread_rwlock_unlock(&global_ctx->fs_fix_rwlock);
+}
+
+void e2fsck_pass1_block_map_w_lock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ pthread_rwlock_wrlock(&global_ctx->fs_block_map_rwlock);
+}
+
+void e2fsck_pass1_block_map_w_unlock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ pthread_rwlock_unlock(&global_ctx->fs_block_map_rwlock);
+}
+
+void e2fsck_pass1_block_map_r_lock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ pthread_rwlock_rdlock(&global_ctx->fs_block_map_rwlock);
+}
+
+void e2fsck_pass1_block_map_r_unlock(e2fsck_t ctx)
+{
+ if (!ctx->fs_need_locking)
+ return;
+ e2fsck_get_lock_context(ctx);
+ pthread_rwlock_unlock(&global_ctx->fs_block_map_rwlock);
+ }
+#else
+void e2fsck_pass1_fix_lock(e2fsck_t ctx)
+{
+
+}
+
+void e2fsck_pass1_fix_unlock(e2fsck_t ctx)
+{
+
+}
+void e2fsck_pass1_check_lock(e2fsck_t ctx)
+{
+
+}
+void e2fsck_pass1_check_unlock(e2fsck_t ctx)
+{
+
+}
+void e2fsck_pass1_block_map_w_lock(e2fsck_t ctx)
+{
+
+}
+
+void e2fsck_pass1_block_map_w_unlock(e2fsck_t ctx)
+{
+
+}
+
+void e2fsck_pass1_block_map_r_lock(e2fsck_t ctx)
+{
+
+}
+
+void e2fsck_pass1_block_map_r_unlock(e2fsck_t ctx)
+{
+
+}
+#endif
+
void e2fsck_write_inode_full(e2fsck_t ctx, unsigned long ino,
struct ext2_inode * inode, int bufsize,
const char *proc)
{
errcode_t retval;
+ e2fsck_pass1_fix_lock(ctx);
retval = ext2fs_write_inode_full(ctx->fs, ino, inode, bufsize);
+ e2fsck_pass1_fix_unlock(ctx);
if (retval) {
com_err("ext2fs_write_inode", retval,
_("while writing inode %lu in %s"), ino, proc);
{
errcode_t retval;
+ e2fsck_pass1_fix_lock(ctx);
retval = ext2fs_write_inode(ctx->fs, ino, inode);
+ e2fsck_pass1_fix_unlock(ctx);
if (retval) {
com_err("ext2fs_write_inode", retval,
_("while writing inode %lu in %s"), ino, proc);
/*
* Helper function that does the right thing if write returns a
- * partial write, or an EGAIN/EINTR error.
+ * partial write, or an EAGAIN/EINTR error.
*/
int write_all(int fd, char *buf, size_t count)
{
return c;
}
-void dump_mmp_msg(struct mmp_struct *mmp, const char *msg)
+void dump_mmp_msg(struct mmp_struct *mmp, const char *fmt, ...)
{
+ va_list pvar;
- if (msg)
- printf("MMP check failed: %s\n", msg);
+ if (fmt) {
+ printf("MMP check failed: ");
+ va_start(pvar, fmt);
+ vprintf(fmt, pvar);
+ va_end(pvar);
+ }
if (mmp) {
time_t t = mmp->mmp_time;
- printf("MMP error info: last update: %s node: %s device: %s\n",
- ctime(&t), mmp->mmp_nodename, mmp->mmp_bdevname);
+ printf("MMP_block:\n");
+ printf(" mmp_magic: 0x%x\n", mmp->mmp_magic);
+ printf(" mmp_check_interval: %d\n",
+ mmp->mmp_check_interval);
+ printf(" mmp_sequence: %08x\n", mmp->mmp_seq);
+ printf(" mmp_update_date: %s", ctime(&t));
+ printf(" mmp_update_time: %lld\n",
+ (long long) mmp->mmp_time);
+ printf(" mmp_node_name: %.*s\n",
+ EXT2_LEN_STR(mmp->mmp_nodename));
+ printf(" mmp_device_name: %.*s\n",
+ EXT2_LEN_STR(mmp->mmp_bdevname));
}
}
fs->default_bitmap_type = save_type;
return retval;
}
+
+/* Return memory size in bytes */
+unsigned long long get_memory_size(void)
+{
+#if defined(_SC_PHYS_PAGES)
+# if defined(_SC_PAGESIZE)
+ return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
+ (unsigned long long)sysconf(_SC_PAGESIZE);
+# elif defined(_SC_PAGE_SIZE)
+ return (unsigned long long)sysconf(_SC_PHYS_PAGES) *
+ (unsigned long long)sysconf(_SC_PAGE_SIZE);
+# endif
+#elif defined(CTL_HW)
+# if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
+# define CTL_HW_INT64
+# elif (defined(HW_PHYSMEM) || defined(HW_REALMEM))
+# define CTL_HW_UINT
+# endif
+ int mib[2];
+
+ mib[0] = CTL_HW;
+# if defined(HW_MEMSIZE)
+ mib[1] = HW_MEMSIZE;
+# elif defined(HW_PHYSMEM64)
+ mib[1] = HW_PHYSMEM64;
+# elif defined(HW_REALMEM)
+ mib[1] = HW_REALMEM;
+# elif defined(HW_PYSMEM)
+ mib[1] = HW_PHYSMEM;
+# endif
+# if defined(CTL_HW_INT64)
+ unsigned long long size = 0;
+# elif defined(CTL_HW_UINT)
+ unsigned int size = 0;
+# endif
+ return 0;
+#else
+# warning "Don't know how to detect memory on your platform?"
+ return 0;
+#endif
+}