Пример #1
0
static void
limit_bandwidth (wgint bytes, struct ptimer *timer)
{
  double delta_t = ptimer_read (timer) - limit_data.chunk_start;
  double expected;

  limit_data.chunk_bytes += bytes;

  /* Calculate the amount of time we expect downloading the chunk
     should take.  If in reality it took less time, sleep to
     compensate for the difference.  */
  expected = (double) limit_data.chunk_bytes / opt.limit_rate;

  if (expected > delta_t)
    {
      double slp = expected - delta_t + limit_data.sleep_adjust;
      double t0, t1;
      if (slp < 0.2)
        {
          DEBUGP (("deferring a %.2f ms sleep (%s/%.2f).\n",
                   slp * 1000, number_to_static_string (limit_data.chunk_bytes),
                   delta_t));
          return;
        }

      if (slp > 1) // VisualWget: We do not expect to sleep more than 1 second.
        slp = 1;

      DEBUGP (("\nsleeping %.2f ms for %s bytes, adjust %.2f ms\n",
               slp * 1000, number_to_static_string (limit_data.chunk_bytes),
               limit_data.sleep_adjust));

      t0 = ptimer_read (timer);
      xsleep (slp);
      t1 = ptimer_measure (timer);

      /* Due to scheduling, we probably slept slightly longer (or
         shorter) than desired.  Calculate the difference between the
         desired and the actual sleep, and adjust the next sleep by
         that amount.  */
      limit_data.sleep_adjust = slp - (t1 - t0);
      /* If sleep_adjust is very large, it's likely due to suspension
         and not clock inaccuracy.  Don't enforce those.  */
      if (limit_data.sleep_adjust > 0.5)
        limit_data.sleep_adjust = 0.5;
      else if (limit_data.sleep_adjust < -0.5)
        limit_data.sleep_adjust = -0.5;
    }

  limit_data.chunk_bytes = 0;
  limit_data.chunk_start = ptimer_read (timer);
}
Пример #2
0
void GetBlockTemplateContext::queryWork()
{
  // JSON-request creation
  char *request;
  {
    blktemplate_t *t = blktmpl_create();
    json_t *jsonRequest = blktmpl_request_jansson(blktmpl_addcaps(t), 0);
    request = json_dumps(jsonRequest, JSON_INDENT(2));
    json_delete(jsonRequest);  
    blktmpl_free(t);
  }
  
  curl_slist *header = curl_slist_append(0, "User-Agent: xpmminer");
  curl_slist_append(header, "Content-Type: application/json");
  
  CURL *curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_URL, _url);
  curl_easy_setopt(curl, CURLOPT_POST, 1L);
  curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  curl_easy_setopt(curl, CURLOPT_USERNAME, _user);
  curl_easy_setopt(curl, CURLOPT_PASSWORD, _password);
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);  
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
  
  while (1) {
    _response.clear();
    if (curl_easy_perform(curl) != CURLE_OK) {
      logFormattedWrite(_log, "block receiving error!");
    } else {
      updateWork();
    }
    
    xsleep(_timeout);
  }
}
Пример #3
0
static void
monitor_daemon(pid_t daemon_pid)
{
    /* XXX Should log daemon's stderr output at startup time. */
    time_t last_restart;
    char *status_msg;
    int crashes;

    set_subprogram_name("monitor");
    status_msg = xstrdup("healthy");
    last_restart = TIME_MIN;
    crashes = 0;
    for (;;) {
        int retval;
        int status;

        proctitle_set("monitoring pid %lu (%s)",
                      (unsigned long int) daemon_pid, status_msg);

        do {
            retval = waitpid(daemon_pid, &status, 0);
        } while (retval == -1 && errno == EINTR);

        if (retval == -1) {
            VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno));
        } else if (retval == daemon_pid) {
            char *s = process_status_msg(status);
            if (should_restart(status)) {
                free(status_msg);
                status_msg = xasprintf("%d crashes: pid %lu died, %s",
                                       ++crashes,
                                       (unsigned long int) daemon_pid, s);
                free(s);

                if (WCOREDUMP(status)) {
                    /* Disable further core dumps to save disk space. */
                    struct rlimit r;

                    r.rlim_cur = 0;
                    r.rlim_max = 0;
                    if (setrlimit(RLIMIT_CORE, &r) == -1) {
                        VLOG_WARN("failed to disable core dumps: %s",
                                  ovs_strerror(errno));
                    }
                }

                /* Throttle restarts to no more than once every 10 seconds. */
                if (time(NULL) < last_restart + 10) {
                    VLOG_WARN("%s, waiting until 10 seconds since last "
                              "restart", status_msg);
                    for (;;) {
                        time_t now = time(NULL);
                        time_t wakeup = last_restart + 10;
                        if (now >= wakeup) {
                            break;
                        }
                        xsleep(wakeup - now);
                    }
                }
                last_restart = time(NULL);

                VLOG_ERR("%s, restarting", status_msg);
                daemon_pid = fork_and_wait_for_startup(&daemonize_fd);
                if (!daemon_pid) {
                    break;
                }
            } else {
                VLOG_INFO("pid %lu died, %s, exiting",
                          (unsigned long int) daemon_pid, s);
                free(s);
                exit(0);
            }
        }
    }
    free(status_msg);

    /* Running in new daemon process. */
    proctitle_restore();
    set_subprogram_name("");
}
Пример #4
0
int main(int argc,
         char *argv[])
{
    int i, j, t;
    int n_tids = 0;
    thread_t tid[256];
    time_t start_time, stop_time;


    signal(SIGPIPE, SIG_IGN);

    for (i = 1; i < argc && argv[i][0] == '-'; i++)
        switch (argv[i][1])
        {
        case '?':
        case 'H':
            exit(help(argv[0]));
            break;

        case 'd':
            debug = atoi(argv[i]+2);
            break;

        case 'R':
            rcvbuf_size = atoi(argv[i]+2);
            break;

        case 't':
            test_length = atoi(argv[i]+2);
            break;

        case 'h':
            server_host = argv[i]+2;
            break;

        case 'p':
            server_port = argv[i]+2;
            break;

        case 'b':
            if (isdigit(argv[i][2]))
                bound_threads = atoi(argv[i]+2);
            else
                bound_threads = 1;
            break;

        case 'c':
            concurrency = atoi(argv[i]+2);
            break;

        case 'E':
            use_exit = 1;
            break;

        case 'e':
            expected_bytes = atoi(argv[i]+2);
            break;

        case 'r':
            repeat = atoi(argv[i]+2);
            break;

        case 'k':
            keepalive = atoi(argv[i]+2);
            break;

        case '0':
            http_0 = 1;
            break;

        default:
            fprintf(stderr, "%s: unknown switch '%s', try -H for help\n",
                    argv[0], argv[1]);
            exit(1);
        }

    keepalive++;

    mutex_init(&result_lock, USYNC_THREAD, NULL);

    if (mksockaddr_in(server_host, server_port, &server_addr) < 0)
    {
        fprintf(stderr, "Error creating socket address\n");
        exit(1);
    }

    fprintf(stderr, "Running test: ");

    for (t = 0; t < test_length; t++)
    {
        if (t % 10)
            putc('-', stderr);
        else
            putc('+', stderr);
    }

    fprintf(stderr, "\rRunning test: ");

    if (concurrency > 0)
        thr_setconcurrency(concurrency);

    time(&start_time);

    for (; i < argc; i++)
    {
        for (j = 0; j < repeat; j++)
        {
            if (thr_create(NULL,
                           0,
                           (void *(*)(void *)) test_thread,
                           (void *) argv[i],
                           (bound_threads ? THR_BOUND : 0) +
                           THR_NEW_LWP,
                           &tid[n_tids]))
            {
                perror("thr_create");
                exit(1);
            }

            n_tids++;
        }
    }

    for (t = 0; t < test_length; t++)
    {
        xsleep(1);
        putc('>', stderr);
        fflush(stdout);
    }

    putc('\n', stderr);
    putc('\n', stderr);

    printf("%-19s %4s  %6s %6s %6s  %6s %6s %6s  %s\n",
           "URL",
           "NRq",
           "Min Ct",
           "Avg Ct",
           "Max Ct",
           "Min Tx",
           "Avg Tx",
           "Max Tx",
           "Bytes");

    stop_flag = 1;

    for (i = 0; i < n_tids; i++)
        thr_join(tid[i], NULL, NULL);

    if (failure)
        exit(1);

    time(&stop_time);

    test_length = (int) stop_time - (int) start_time;

    putchar('\n');

    printf("Actual test time.. %d seconds\n", test_length);

    printf("Total requests.... %d (%d requests/sec)\n",
           total_nrq,
           total_nrq / test_length);

    printf("Total failed...... %d (%d requests/sec)\n",
           total_failed,
           total_failed / test_length);

    printf("Total bytes....... %d (%d bytes/sec)\n",
           total_bytes,
           total_bytes / test_length);

    putchar('\n');
    printf("Min Tx: %.4f\n", min_tx);
    printf("Max Tx: %.4f\n", max_tx);

    exit(0);
}
Пример #5
0
/* racer create a new thread and access the metadata/itb file randomizely
 */
void *racer(void *arg)
{
    struct itb *itb;
    struct fdhash_entry *fde;
    struct itb_info ii;
    u64 duuid = (u64)arg;
    struct mmap_args ma = {0, };
    range_t *range;
    int len, range_begin, range_end, err, counter = 0;

    itb = xmalloc(sizeof(*itb) + ITB_SIZE * sizeof(struct ite));
    if (!itb) {
        hvfs_err(mdsl, "xmalloc ITB failed\n");
        racer_stop = 1;
    }
    range_begin = sizeof(itb->h);
    range_end = sizeof(*itb) + ITB_SIZE * sizeof(struct ite);

    while (!racer_stop) {
        xsleep(lib_random(0xffff));
        /* try to append more itb to the itb file */
        len = lib_random(range_end - range_begin) + range_begin;
        atomic_set(&itb->h.len, len);
        itb->h.itbid = lib_random(0xfff);
        itb->h.puuid = duuid;

        err = itb_append(itb, &ii, hmo.site_id, 0);
        if (err) {
            hvfs_err(mdsl, "Append itb <> to disk file failed w/ %d\n",
                     err);
            continue;
        } else {
            hvfs_info(mdsl, "Append (%d) itb %ld len %d to itb file %ld\n",
                      (++counter), itb->h.itbid, atomic_read(&itb->h.len),
                      ii.master);
        }
        /* open the md file and try to update the ranges */
        fde = mdsl_storage_fd_lookup_create(duuid, MDSL_STORAGE_MD, 0);
        if (IS_ERR(fde)) {
            hvfs_err(mdsl, "lookup create MD file failed w/ %ld\n",
                     PTR_ERR(fde));
            continue;
        }
        if (ii.master < fde->mdisk.itb_master) {
            hvfs_info(mdsl, "Drop obsolete itb %ld appending %ld\n",
                      itb->h.itbid, ii.location);
            goto put_fde;
        }
        ma.win = MDSL_STORAGE_DEFAULT_RANGE_SIZE;
    relookup:
        xlock_lock(&fde->lock);
        err = __mdisk_lookup_nolock(fde, MDSL_MDISK_RANGE, itb->h.itbid,
                                    &range);
        if (err == -ENOENT) {
            /* create a new range now */
            u64 i;
            
            i = MDSL_STORAGE_idx2range(itb->h.itbid);
            __mdisk_add_range_nolock(fde, i * MDSL_STORAGE_RANGE_SLOTS,
                                     (i + 1) * MDSL_STORAGE_RANGE_SLOTS - 1,
                                     fde->mdisk.range_aid++);
            __mdisk_range_sort(fde->mdisk.new_range, fde->mdisk.new_size);
            xlock_unlock(&fde->lock);
            goto relookup;
        } else if (err) {
            hvfs_err(mdsl, "mdisk_lookup_nolock failed w/ %d\n", err);
            xlock_unlock(&fde->lock);
            goto put_fde;
        }
        xlock_unlock(&fde->lock);

        ma.foffset = 0;
        ma.range_id = range->range_id;
        ma.range_begin = range->begin;
        ma.flag = MA_OFFICIAL;

        err = __range_write(duuid, itb->h.itbid, &ma, ii.location);
        if (err) {
            hvfs_err(mdsl, "range write failed w/ %d\n", err);
            goto put_fde;
        }
        err = __mdisk_write(fde, NULL);
        if (err) {
            hvfs_err(mdsl, "sync md file failed w/ %d\n", err);
        }
    put_fde:
        mdsl_storage_fd_put(fde);
    }

    pthread_exit(0);
}
Пример #6
0
int itb_gc_append(int gen, struct itb *itb, struct itb_info *ii)
{
    int err = 0;

    if (unlikely(hmo.conf.option & HVFS_MDSL_WDROP))
        return 0;

    if (ii) {
        struct fdhash_entry *fde;
        struct iovec itb_iov = {
            .iov_base = itb,
            .iov_len = atomic_read(&itb->h.len),
        };
        struct mdsl_storage_access msa = {
            .iov = &itb_iov,
            .arg = ii,
            .iov_nr = 1,
        };

        /* prepare write to the file: "[target dir]/itb-*" */
        fde = mdsl_storage_fd_lookup_create(itb->h.puuid, MDSL_STORAGE_ITB,
                                            gen);
        if (IS_ERR(fde)) {
            hvfs_err(mdsl, "lookup create failed w/ %ld\n", PTR_ERR(fde));
            goto out;
        }
        err = mdsl_storage_fd_write(fde, &msa);
        if (err) {
            hvfs_err(mdsl, "storage_fd_write failed w/ %d\n", err);
            mdsl_storage_fd_put(fde);
            goto out;
        }
        if (unlikely(ii->location == 0)) {
            hvfs_err(mdsl, "Write ITB %ld[%lx] len %d to storage file off "
                   "%ld fde ST %x.\n",
                   itb->h.itbid, itb->h.puuid, 
                   atomic_read(&itb->h.len), ii->location, 
                   fde->state);
            HVFS_BUGON("zero location!");
        }
        mdsl_storage_fd_put(fde);
        /* accumulate to hmi */
        atomic64_add(itb_iov.iov_len, &hmi.mi_bused);
    }

out:
    return err;
}

/* do GC-TX on itb file change
 *
 * write the tx_begin in hmo.storage.gc_fd
 * write the tx_end in hmo.storage.gc_fd
 *
 * Rational:
 * 1. for md file, we copy the md-1 file to md-0 (replace the ranges);
 * 2. for range files, we rename Grange-* to range-*;
 * 3. for itb file, we adjust mdisk.master to the new itb file;
 */
int mdsl_gc_tx_itb(u64 duuid, int gen, struct fdhash_entry *omd)
{
    struct fdhash_entry *fde;
    int err = 0, i, j, abort_flag;

    hvfs_info(mdsl, "BEGIN GC-MD transaction on directoy %ld gen %d\n",
              duuid, gen);
    fde = mdsl_storage_fd_lookup_create(duuid, MDSL_STORAGE_MD, gen);
    if (IS_ERR(fde)) {
        hvfs_err(mdsl, "lookup create gc MD file failed w/ %ld\n",
                 PTR_ERR(fde));
        err = PTR_ERR(fde);
        goto out;
    }
    
    /* Save the old and new md file */
    err = __mdisk_write(omd, NULL);
    if (err) {
        hvfs_err(mdsl, "sync md file failed w/ %d\n", err);
        /* if old md file is failed to be saved, we abort transaction */
        goto out;
    }
    err = __mdisk_write(fde, NULL);
    if (err) {
        hvfs_err(mdsl, "sync gc md file failed w/ %d\n", err);
    }
    
    /* we know the omd file has already been LOCKED, thus we just copy the new
     * md file's range to old md file */
    xfree(omd->mdisk.ranges);
    xfree(omd->mdisk.new_range);
    omd->mdisk.range_nr[0] = fde->mdisk.range_nr[0];
    omd->mdisk.size = fde->mdisk.size;
    omd->mdisk.new_size = fde->mdisk.new_size;
    omd->mdisk.new_range = fde->mdisk.new_range;
    omd->mdisk.ranges = fde->mdisk.ranges;
    omd->mdisk.range_aid = fde->mdisk.range_aid;

    /* for range files, we do rename */
    if (omd->mdisk.ranges) {
        for (i = 0; i < fde->mdisk.size; i++) {
            char opath[256], npath[256];

            abort_flag = 0;
            sprintf(opath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME, 
                    hmo.site_id, duuid, (fde->mdisk.ranges + i)->range_id);
            sprintf(npath, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME,
                    hmo.site_id, duuid, (fde->mdisk.ranges + i)->range_id);
            err = rename(opath, npath);
            if (err) {
                if (errno == ENOENT) {
                    /* I think it is ok that there is a new range created in
                     * the new metadata file, thus, we just ignore this error */
                    hvfs_warning(mdsl, "Rename '%s' but it doesn't exist!\n",
                                 opath);
                } else {
                    hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d\n",
                             opath, npath, errno);
                    err = -errno;
                    goto rollback_ranges;
                }
            }
            abort_flag = 1;
            
            sprintf(opath, "%s/%lx/%lx/Grange-%ld", HVFS_MDSL_HOME, 
                    hmo.site_id, duuid, (fde->mdisk.ranges + i)->range_id);
            sprintf(npath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME,
                    hmo.site_id, duuid, (fde->mdisk.ranges + i)->range_id);
            err = rename(opath, npath);
            if (err) {
                hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d\n",
                         opath, npath, errno);
                err = -errno;
                goto rollback_ranges;
            }
        }
    }
    if (omd->mdisk.new_range) {
        for (i = 0; i < fde->mdisk.new_size; i++) {
            char opath[256], npath[256];

            abort_flag = 0;
            sprintf(opath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME, 
                    hmo.site_id, duuid, (fde->mdisk.new_range + i)->range_id);
            sprintf(npath, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME,
                    hmo.site_id, duuid, (fde->mdisk.new_range + i)->range_id);
            err = rename(opath, npath);
            if (err) {
                hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d\n",
                         opath, npath, errno);
                err = -errno;
                goto rollback_new_range;
            }
            abort_flag = 1;
            
            sprintf(opath, "%s/%lx/%lx/Grange-%ld", HVFS_MDSL_HOME, 
                    hmo.site_id, duuid, (fde->mdisk.new_range + i)->range_id);
            sprintf(npath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME,
                    hmo.site_id, duuid, (fde->mdisk.new_range + i)->range_id);
            err = rename(opath, npath);
            if (err) {
                hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d\n",
                         opath, npath, errno);
                err = -errno;
                goto rollback_new_range;
            }
        }
    }
    /* final step, atomic change to the new itb file and do cleanups */
    omd->mdisk.itb_master++;
    /* FIXME: cleanup range files(Brange-* and old itb file) */
    err = __mdisk_write(omd, NULL);
    if (err) {
        hvfs_err(mdsl, "sync md file failed w/ %d\n", err);

        i = fde->mdisk.new_size;
        abort_flag = 0;
        goto rollback_new_range;
    }
    /* remove the new md file */
    mdsl_storage_fd_remove(fde);
    close(fde->fd);
    {
        char path[256];

        sprintf(path, "%s/%lx/%lx/md-%d", HVFS_MDSL_HOME,
                hmo.site_id, duuid, gen);
        err = unlink(path);
        if (err) {
            hvfs_err(mdsl, "Unlink '%s' failed w/ %d, need human involving\n", 
                     path, err);
        }
    }
    /* remove the Brange files and old itb file */
    {
        char path[256];

        sprintf(path, "%s/%lx/%lx/itb-%d", HVFS_MDSL_HOME,
                hmo.site_id, duuid, gen - 1);
        err = unlink(path);
        if (err) {
            hvfs_err(mdsl, "Unlink '%s' failed w/ %d, need human involving\n",
                     path, err);
        }
    }
    {
        if (omd->mdisk.ranges) {
            for (i = 0; i < omd->mdisk.size; i++) {
                char path[256];

                sprintf(path, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME,
                        hmo.site_id, duuid, (omd->mdisk.ranges + i)->range_id);
                err = unlink(path);
                if (err) {
                    hvfs_err(mdsl, "Unlink '%s' failed w/ %d, need human "
                             "involving\n",
                             path, err);
                }
            }
        }
        if (omd->mdisk.new_range) {
            for (i = 0; i < omd->mdisk.new_size; i++) {
                char path[256];

                sprintf(path, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME,
                        hmo.site_id, duuid, 
                        (omd->mdisk.new_range + i)->range_id);
                err = unlink(path);
                if (err) {
                    hvfs_err(mdsl, "Unlink '%s' failed w/ %d, need human "
                             "involving\n",
                             path, err);
                }
            }
        }
    }

    hvfs_info(mdsl, "END GC-MD transaction on directory %ld gen %d\n",
              duuid ,gen);
    goto out;
    
out_put:
    mdsl_storage_fd_put(fde);
out:
    return err;
rollback_new_range:
    for (j = 0; j < i; j++) {
        char opath[256], npath[256];
        
        sprintf(opath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME, 
                hmo.site_id, duuid, (fde->mdisk.new_range + j)->range_id);
        sprintf(npath, "%s/%lx/%lx/Grange-%ld", HVFS_MDSL_HOME,
                hmo.site_id, duuid, (fde->mdisk.new_range + j)->range_id);
        err = rename(opath, npath);
        if (err) {
            hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d, request "
                     "for human involving\n",
                     opath, npath, errno);
        }

        sprintf(opath, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME, 
                hmo.site_id, duuid, (fde->mdisk.new_range + j)->range_id);
        sprintf(npath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME,
                hmo.site_id, duuid, (fde->mdisk.new_range + j)->range_id);
        err = rename(opath, npath);
        if (err) {
            hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d, request "
                     "for human involving\n",
                     opath, npath, errno);
        }
    }
    if (abort_flag) {
        char opath[256], npath[256];
        
        sprintf(opath, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME, 
                hmo.site_id, duuid, (fde->mdisk.new_range + i)->range_id);
        sprintf(npath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME,
                hmo.site_id, duuid, (fde->mdisk.new_range + i)->range_id);
        err = rename(opath, npath);
        if (err) {
            hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d, request "
                     "for human involving\n",
                     opath, npath, errno);
        }
    }
    /* reset flag and size for rollback of ranges! */
    abort_flag = 0;
    i = fde->mdisk.size;
rollback_ranges:
    for (j = 0; j < i; j++) {
        char opath[256], npath[256];
        
        sprintf(opath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME, 
                hmo.site_id, duuid, (fde->mdisk.ranges + j)->range_id);
        sprintf(npath, "%s/%lx/%lx/Grange-%ld", HVFS_MDSL_HOME,
                hmo.site_id, duuid, (fde->mdisk.ranges + j)->range_id);
        err = rename(opath, npath);
        if (err) {
            hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d, request "
                     "for human involving\n",
                     opath, npath, errno);
        }

        sprintf(opath, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME, 
                hmo.site_id, duuid, (fde->mdisk.ranges + j)->range_id);
        sprintf(npath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME,
                hmo.site_id, duuid, (fde->mdisk.ranges + j)->range_id);
        err = rename(opath, npath);
        if (err) {
            hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d, request "
                     "for human involving\n",
                     opath, npath, errno);
        }
    }
    if (abort_flag) {
        char opath[256], npath[256];
        
        sprintf(opath, "%s/%lx/%lx/Brange-%ld", HVFS_MDSL_HOME, 
                hmo.site_id, duuid, (fde->mdisk.ranges + i)->range_id);
        sprintf(npath, "%s/%lx/%lx/range-%ld", HVFS_MDSL_HOME,
                hmo.site_id, duuid, (fde->mdisk.ranges + i)->range_id);
        err = rename(opath, npath);
        if (err) {
            hvfs_err(mdsl, "Rename '%s' to '%s' failed w/ %d, request "
                     "for human involving\n",
                     opath, npath, errno);
        }
    }
    /* rollback mdisk */
    omd->state = FDE_OPEN;
    err = mdsl_storage_fd_mdisk(omd, NULL);
    if (err) {
        hvfs_err(mdsl, "Reload mdisk from disk failed w/ %d. CRASH is "
                 "nearing\n", err);
    }
    err = -EABORT;
    hvfs_info(mdsl, "ABORT GC-MD transaction on directory %ld gen %d\n",
              duuid, gen);
    goto out_put;
}

/* GC one round of the metadata
 *
 * Return Value: >=0: # of ITBs we handled; <0: error
 */
int mdsl_gc_md_round(u64 duuid, int master, struct fdhash_entry *md, 
                     struct fdhash_entry *fde, u64 *gc_offset)
{
    struct itb_info ii = {
        .duuid = duuid,
    };
    struct itb *itb;
    struct fdhash_entry *nmd;
    range_t *range;
    struct iovec itb_iov;
    struct mdsl_storage_access msa = {
        .iov = &itb_iov,
        .iov_nr = 1,
    };
    struct mmap_args ma;
    u64 offset = *gc_offset, location = 0;
    int err = 0, data_len, compacted = 0, handled = 0, missed = 0;

    if (offset == -1UL) {
        return -EINVAL;
    }
    if (!offset) {
        /* adjust offset to 1! */
        offset = 1;
    }

    if (!md->mdisk.ranges && !md->mdisk.new_range) {
        return -ENOENT;
    }

    itb = xmalloc(sizeof(struct itb) + ITB_SIZE * sizeof(struct ite));
    if (!itb) {
        hvfs_err(mdsl, "xzalloc() itb failed.\n");
        return -ENOMEM;
    }
    
    while (1) {
        /* prepare itb */
        memset(itb, 0, sizeof(struct itb) + ITB_SIZE * sizeof(struct ite));
        /* read the header */
        msa.offset = offset;
        itb_iov.iov_base = itb;
        itb_iov.iov_len = sizeof(itb->h);
        if (offset >= fde->abuf.file_offset + fde->abuf.offset) {
            break;
        }
        err = mdsl_storage_fd_read(fde, &msa);
        if (err) {
            hvfs_err(mdsl, "fd read failed w/ %d\n", err);
            goto out_free;
        }
        if (!atomic_read(&itb->h.len)) {
            /* we should seek to next active page! */
            u64 last_offset;

        reskip:
            last_offset = offset;
            offset = PAGE_ROUNDUP(offset, getpagesize());
            if (offset == last_offset) {
                offset += 1;
                goto reskip;
            }
            continue;
        }

        handled++;
        /* compare this itb with the latest offset */
        ma.win = MDSL_STORAGE_DEFAULT_RANGE_SIZE;

        err = __mdisk_lookup(md, MDSL_MDISK_RANGE, itb->h.itbid, &range);
        if (err == -ENOENT) {
            /* it is ok */
            missed++;
            hvfs_warning(mdsl, "lookup itbid %ld in md file failed w/ %d\n",
                         itb->h.itbid, err);
            goto compact_it;
        } else if (err) {
            hvfs_err(mdsl, "lookup itbid %ld in old md file failed w/ %d\n",
                     itb->h.itbid, err);
            goto out_free;
        }
        ma.foffset = 0;
        ma.range_id = range->range_id;
        ma.range_begin = range->begin;
        ma.flag = MA_OFFICIAL;

        err = __range_lookup(duuid, itb->h.itbid, &ma, &location);
        if (err) {
            goto out_free;
        }
        /* if location is ZERO, it means that the racer has not been update
         * the range file, we just compact this entry to the new itb file to
         * not lose any itb. */
        if (!location) {
            missed++;
            hvfs_warning(mdsl, "lookup itbid %ld in range file "
                         "failed w/ ENOENT\n",
                         itb->h.itbid);
            goto compact_it;
        }

        if (offset == location) {
            compacted++;
        compact_it:
            /* read in the data region of itb */
            data_len = atomic_read(&itb->h.len) - sizeof(itb->h);
            if (data_len > 0) {
                msa.offset = offset + sizeof(itb->h);
                msa.iov->iov_base = &itb->lock;
                msa.iov->iov_len = data_len;
                err = mdsl_storage_fd_read(fde, &msa);
                if (err) {
                    hvfs_err(mdsl, "fd read failed w/ %d\n", err);
                    goto out_free;
                }
            } else {
                hvfs_err(mdsl, "data_len %d is minus, internal error!\n", 
                         data_len);
                err = -EFAULT;
                goto out_free;
            }
            /* ok, we should copy this itb entry to the new itb file */
            ii.itbid = itb->h.itbid;
            ASSERT(itb->h.puuid == duuid, mdsl);
            err = itb_gc_append(master + 1, itb, &ii);
            if (err) {
                hvfs_err(mdsl, "GC append itb %ld to new file failed w/ %d\n",
                         itb->h.itbid, err);
                goto out_free;
            }
            /* open the gc_md file and update the gc range region */
            nmd = mdsl_storage_fd_lookup_create(duuid, MDSL_STORAGE_MD, 
                                                master + 1);
            if (IS_ERR(nmd)) {
                hvfs_err(mdsl, "lookup create gc MD file failed w/ %ld\n",
                         PTR_ERR(nmd));
                err = PTR_ERR(nmd);
                goto out_free;
            }
            ma.win = MDSL_STORAGE_DEFAULT_RANGE_SIZE;
        relookup:
            xlock_lock(&nmd->lock);
            err = __mdisk_lookup_nolock(nmd, MDSL_MDISK_RANGE, 
                                        itb->h.itbid, &range);
            if (err == -ENOENT) {
                /* create a new range now */
                u64 i;

                i = MDSL_STORAGE_idx2range(itb->h.itbid);
                __mdisk_add_range_nolock(nmd, i * MDSL_STORAGE_RANGE_SLOTS,
                                         (i + 1) * MDSL_STORAGE_RANGE_SLOTS - 1,
                                         nmd->mdisk.range_aid++);
                __mdisk_range_sort(nmd->mdisk.new_range, nmd->mdisk.new_size);
                xlock_unlock(&nmd->lock);
                goto relookup;
            } else if (err) {
                hvfs_err(mdsl, "mdisk_lookup_nolock failed w/ %d\n", err);
                xlock_unlock(&nmd->lock);
                goto put_fde;
            }
            xlock_unlock(&nmd->lock);

            ma.foffset = 0;
            ma.range_id = range->range_id;
            ma.range_begin = range->begin;
            ma.flag = MA_GC;

            err = __range_write(duuid, itb->h.itbid, &ma, ii.location);
            if (err) {
                hvfs_err(mdsl, "range write failed w/ %d\n", err);
                goto put_fde;
            }
            err = __mdisk_write(nmd, NULL);
            if (err) {
                hvfs_err(mdsl, "sync gc md file failed w/ %d\n", err);
            }
            
        put_fde:
            mdsl_storage_fd_put(nmd);
            if (err) {
                goto out_free;
            }
        }
        /* ok, this itb is done. handle the next one */
        hvfs_warning(mdsl, "Process itb %ld len %d (%s) done. LOC %ld\n", 
                     itb->h.itbid, atomic_read(&itb->h.len), 
                     (offset == location ? "+" : "."),
                     ii.location);
        offset += atomic_read(&itb->h.len);
    }
    err = compacted;
    hvfs_info(mdsl, "This round handled %s%d%s, compacted %s%d%s "
              "and missed %s%d%s ITBs.\n",
              HVFS_COLOR_RED, handled, HVFS_COLOR_END,
              HVFS_COLOR_GREEN, compacted, HVFS_COLOR_END,
              HVFS_COLOR_YELLOW, missed, HVFS_COLOR_END);
    
out_free:
    xfree(itb);
    *gc_offset = offset;

    return err;
}

/* GC the medata of directory duuid
 */
int mdsl_gc_md(u64 duuid)
{
    struct fdhash_entry *fde, *itbf;
    u64 last_offset, gc_offset;
    int err = 0, round = 0, master;
    
    /* Step 0: prepare: open the md file */
    fde = mdsl_storage_fd_lookup_create(duuid, MDSL_STORAGE_MD, 0);
    if (IS_ERR(fde)) {
        hvfs_err(mdsl, "lookup create MD file failed w/ %ld\n", PTR_ERR(fde));
        err = PTR_ERR(fde);
        goto out;
    }

    /* Step 1: issue one round to scan the itb file */
    master = fde->mdisk.itb_master;
    itbf = mdsl_storage_fd_lookup_create(duuid, MDSL_STORAGE_ITB, master);
    if (IS_ERR(itbf)) {
        hvfs_err(mdsl, "lookup create ITB file failed w/ %ld\n", PTR_ERR(itbf));
        err = PTR_ERR(itbf);
        goto out_put;
    }
    
    gc_offset = fde->mdisk.gc_offset;
    last_offset = gc_offset;

redo_round:
    hvfs_warning(mdsl, "GC directory %lx in round %d\n", duuid, round++);
    err = mdsl_gc_md_round(duuid, master, fde, itbf, &gc_offset);
    if (err < 0) {
        hvfs_err(mdsl, "GC metadata in stage %d's round %d failed w/ %d\n",
                 master, round - 1, err);
        goto out_cleanup;
    } else if (err == 0) {
        /* nothing has been handled, we just stop gc */
        hvfs_warning(mdsl, "Not redundant ITB to be compacted!\n");
        goto out_cleanup;
    }
    
    /* Step 2: do check */
    last_offset = mdsl_storage_fd_max_offset(itbf);
    if (last_offset == -1UL) {
        hvfs_err(mdsl, "get the ITB file offset failed\n");
        err = -EINVAL;
        goto out_cleanup;
    }
    
    if (gc_offset < last_offset) {
        /* we need another gc round! */
        goto redo_round;
    }
    
    /* Step 3: lockup the fde and recheck */
    err = mdsl_storage_fd_lockup(fde);
    if (err) {
        hvfs_err(mdsl, "lockup the MD file failed w/ %d\n",
                 err);
        goto out_cleanup;
    }
    /* wait for the last reference of ITB file */
    while (atomic_read(&itbf->ref) > 1) {
        xsleep(100);
    }
    last_offset = mdsl_storage_fd_max_offset(itbf);
    if (last_offset == -1UL) {
        hvfs_err(mdsl, "get the ITB file offset failed\n");
        err = -EINVAL;
        goto out_unlock;
    }
    if (gc_offset < last_offset) {
        /* we need the final gc round! */
        hvfs_warning(mdsl, "GC directory %lx in round %d(final)\n", 
                     duuid, round++);
        err = mdsl_gc_md_round(duuid, master, fde, itbf, &gc_offset);
        if (err) {
            hvfs_err(mdsl, "GC metadata in stage %d's round %d failed w/ %d\n",
                     master, round, err);
            goto out_unlock;
        }
        ASSERT(gc_offset >= last_offset, mdsl);
    }
    /* ok, we should release the memory resouce of ITB file */
    append_buf_destroy_async(itbf); /* already close the fd */
    mdsl_storage_fd_remove(itbf);
    xfree(itbf);
    mdsl_storage_evict_rangef(duuid);
    
    /* Step 4: do GC-TX */
    err = mdsl_gc_tx_itb(duuid, master + 1, fde);
    if (err) {
        hvfs_err(mdsl, "mdsl_gc_tx_itb(%d) failed w/ %d\n",
                 master, err);
        goto out_release;
    }

    /* finally, release the MD's fde */
    fde->mdisk.gc_offset = 0;
    
out_release:
    mdsl_storage_fd_unlock(fde);
    
out_put:
    mdsl_storage_fd_put(fde);
    
out:
    return err;
out_unlock:
    mdsl_storage_fd_unlock(fde);
out_cleanup:
    /* cleanup the round result? do not do that, we remember the gc_offset */
    fde->mdisk.gc_offset = gc_offset;
    mdsl_storage_fd_put(itbf);
    goto out_put;
}
Пример #7
0
/**
 * Do everything before the fork and do everything the exec fork
 * 
 * @param   argc  The number of command line arguments
 * @param   argv  The command line arguments
 */
void do_login(int argc, char** argv)
{
  char* username = NULL;
  char* hostname = NULL;
  char preserve_env = 0;
  int ret;
  #ifdef USE_TTY_GROUP
  struct group* group;
  #endif
  
  
  #if AUTH > 0
  /* Disable echoing */
  passphrase_disable_echo1(STDIN_FILENO /* Will be the terminal. */);
  /* This should be done as early and quickly as possible so as little
     as possible of the passphrase gets leaked to the output if the user
     begins entering the passphrase directly after the username. */
  #endif
  
  
  /* Set process group ID */
  setpgrp();
  
  
  /* Parse command line arguments */
  {
    char double_dashed = 0;
    char hostname_on_next = 0;
    int i;
    for (i = 1; i < argc; i++)
      {
	char *arg = *(argv + i);
	char c;
	
	if (*arg == 0)
	  ;
	else if ((*arg == '-') && (double_dashed == 0))
	  while ((c = *(++arg)))
	    if (c == 'H')
	      ;
	    else if (c == 'V')
	      _exit(2);
	    else if (c == 'p')
	      preserve_env = 1;
	    else if (c == 'h')
	      {
		if (*(arg + 1))
		  hostname = arg + 1;
		else
		  hostname_on_next = 1;
		break;
	      }
	    else if (c == 'f')
	      {
		if (*(arg + 1))
		  username = arg + 1;
		skip_auth = 1;
		break;
	      }
	    else if (c == '-')
	      {
		double_dashed = 1;
		break;
	      }
	    else
	      printf("%s: unrecognised options: -%c\n", *argv, c);
	else if (hostname_on_next)
	  {
	    hostname = arg;
	    hostname_on_next = 0;
	  }
	else
	  username = arg;
      }
  }
  
  
  /* Change that a username has been specified */
  if (username == NULL)
    {
      printf("%s: no username specified\n", *argv);
      sleep(ERROR_SLEEP);
      _exit(2);
    }
  
  
  /* Verify that the user may login */
  ret = fork_exec_wait_hook(HOOK_VERIFY, argc, argv);
  if ((ret >= 0) && WIFEXITED(ret) && (WEXITSTATUS(ret) == 1))
    {
      sleep(ERROR_SLEEP);
      _exit(2);
    }
  
  
  if (skip_auth)
    {
      /* Reset terminal settings */
      passphrase_reenable_echo1(STDIN_FILENO);
      
      /* Only root may bypass authentication */
      if (getuid())
	{
	  printf("%s: only root by use the -f option\n", *argv);
	  sleep(ERROR_SLEEP);
	  _exit(2);
	}
    }
  /* Print ant we want a passphrase, if -f has not been used */
  else
    {
      printf("Passphrase: ");
      fflush(stdout);
    }
  /* Done early to make to program look like it is even faster than it is */
  
  
  /* Make sure nopony is spying */
  #ifdef USE_TTY_GROUP
  if ((group = getgrnam(TTY_GROUP)))
    tty_group = group->gr_gid;
  endgrent();
  #endif
  secure_tty(tty_group);
  
  #if AUTH > 0
  if (skip_auth == 0)
    {
      /* Redisable echoing */
      passphrase_disable_echo1(STDIN_FILENO);
    }
  #endif
  
  
  /* Set up clean quiting and time out */
  signal(SIGALRM, timeout_quit);
  signal(SIGQUIT, user_quit);
  signal(SIGINT, user_quit);
  siginterrupt(SIGALRM, 1);
  siginterrupt(SIGQUIT, 1);
  siginterrupt(SIGINT, 1);
  #if AUTH > 0
  alarm(TIMEOUT_SECONDS);
  #endif
  
  
  /* Get user information */
  if ((entry = getpwnam(username)) == NULL)
    {
      if (errno)
	perror("getpwnam");
      else
	printf("User does not exist\n");
      sleep(ERROR_SLEEP);
      _exit(1);
    }
  endpwent();
  username = entry->pw_name;
  
  
  /* Verify passphrase or other token, if -f has not been used */
  ret = 2;
  #if AUTH == 0
  (void) hostname;
  #else
  initialise_login(hostname, username, read_passphrase);
  if (skip_auth == 0)
    ret = authenticate_login();
  /* Passphrase entered, turn off timeout */
  alarm(0);
  #endif
  if (ret == 2)
    printf("(auto-authenticated)\n");
  if (ret == 0)
    {
      preexit();
      fork_exec_wait_hook(HOOK_DENIED, argc, argv);
      xsleep(FAILURE_SLEEP);
      _exit(1);
    }
  
  preexit();
  
  
  /* Verify account, such as that it is enabled */
  verify_account();
  
  
  /* Run login hook */
  fork_exec_wait_hook(HOOK_LOGIN, argc, argv);
  
  
  /* Partial login */
  chown_tty(entry->pw_uid, tty_group, 0);
  chdir_home(entry);
  ensure_shell(entry);
  set_environ(entry, preserve_env);
  open_login_session();
  
  
  /* Stop signal handling */
  signal(SIGALRM, SIG_DFL);
  signal(SIGQUIT, SIG_DFL);
  signal(SIGTSTP, SIG_IGN);
  
  
  child_pid = fork();
  /* vfork cannot be used as the child changes the user,
     the parent would not be able to chown the TTY */
  
  if (child_pid == -1)
    {
      perror("fork");
      close_login_session();
      sleep(ERROR_SLEEP);
      _exit(1);
    }
  else if (child_pid)
    return; /* Do not go beyond this in the parent */
  
  /* In case the shell does not do this */
  setsid();
  
  /* Set controlling terminal */
  if (ioctl(STDIN_FILENO, TIOCSCTTY, 1))
    perror("TIOCSCTTY");
  signal(SIGINT, SIG_DFL);
  
  /* Partial login */
  ret = entry->pw_uid
    ? initgroups(username, entry->pw_gid) /* supplemental groups for user, can require network     */
    : setgroups(0, NULL);                 /* supplemental groups for root, does not require netork */
  if (ret == -1)
    {
      perror(entry->pw_uid ? "initgroups" : "setgroups");
      sleep(ERROR_SLEEP);
      _exit(1);
    }
  set_user(entry);
  exec_shell(entry);
}