int __get_authtoken_attr(char *name, pwu_repository_t *rep, attrlist *item) { int repositories; int i; int res; repositories = get_ns(rep, PWU_READ); if (repositories == 0) return (PWU_SYSTEM_ERROR); if (repositories == REP_ERANGE) { /* Can't determine where to look. Fall back to NSS */ repositories = REP_NSS; } i = REP_FILES; res = PWU_NOT_FOUND; /* Loop over repositories until the user is found */ while ((i <= REP_LAST) && (res == PWU_NOT_FOUND)) { if (repositories & i) res = rops[i]->getattr(name, item, rep); i <<= 1; } return (res); }
/* * __check_history - check if a user's new password is in the user's * old password history. * * Entry * user = username. * passwd = new clear text password. * rep = repositories to check. * * Exit * PWU_SUCCESS, passwd found in user's old password history. * The caller should only be interested and fail if * PWU_SUCCESS is returned. * PWU_NOT_FOUND, passwd not in user's old password history. * PWU_errors, PWU_ errors from other routines. * */ int __check_history(char *user, char *passwd, pwu_repository_t *rep) { int repositories; int i; int res; repositories = get_ns(rep, PWU_READ); if (repositories == 0) return (PWU_SYSTEM_ERROR); if (repositories == REP_ERANGE) return (PWU_REPOSITORY_ERROR); i = REP_FILES; res = PWU_NOT_FOUND; /* Loop over repositories until the user is found */ while ((i <= REP_LAST) && (res == PWU_NOT_FOUND)) { if (repositories & i) if (rops[i]->checkhistory != NULL) res = rops[i]->checkhistory(user, passwd, rep); i <<= 1; } return (res); }
void run_test(int64_t delay_ns) { for (int i = 0; i <= 25; i++) { int64_t start, finish; start = get_ns(); do_get(key, 0); finish = get_ns(); int64_t elapsed = finish - start; if (i > 0) { printf("%f\n", elapsed / 1e9); fflush(stdout); } do_sleep(delay_ns); } }
//------------------------------------------------ // Do one large block read operation and report. // static void read_and_report_large_block(device* dev, uint8_t* buf) { uint64_t offset = random_large_block_offset(dev); uint64_t start_time = get_ns(); uint64_t stop_time = read_from_device(dev, offset, g_scfg.large_block_ops_bytes, buf); if (stop_time != -1) { histogram_insert_data_point(g_large_block_read_hist, safe_delta_ns(start_time, stop_time)); } }
//------------------------------------------------ // Do one transaction read operation and report. // static void read_and_report(trans_req* read_req, uint8_t* buf) { uint64_t raw_start_time = get_ns(); uint64_t stop_time = read_from_device(read_req->dev, read_req->offset, read_req->size, buf); if (stop_time != -1) { histogram_insert_data_point(g_raw_read_hist, safe_delta_ns(raw_start_time, stop_time)); histogram_insert_data_point(g_read_hist, safe_delta_ns(read_req->start_time, stop_time)); histogram_insert_data_point(read_req->dev->raw_read_hist, safe_delta_ns(raw_start_time, stop_time)); } }
//------------------------------------------------ // Do one large block write operation and report. // static void write_and_report_large_block(device* dev, uint8_t* buf, uint64_t count) { // Salt the block each time. rand_fill(buf, g_scfg.large_block_ops_bytes); uint64_t offset = random_large_block_offset(dev); uint64_t start_time = get_ns(); uint64_t stop_time = write_to_device(dev, offset, g_scfg.large_block_ops_bytes, buf); if (stop_time != -1) { histogram_insert_data_point(g_large_block_write_hist, safe_delta_ns(start_time, stop_time)); } }
//------------------------------------------------ // Do one transaction write operation and report. // static void write_and_report(trans_req* write_req, uint8_t* buf) { // Salt each record. rand_fill(buf, write_req->size); uint64_t raw_start_time = get_ns(); uint64_t stop_time = write_to_device(write_req->dev, write_req->offset, write_req->size, buf); if (stop_time != -1) { histogram_insert_data_point(g_raw_write_hist, safe_delta_ns(raw_start_time, stop_time)); histogram_insert_data_point(g_write_hist, safe_delta_ns(write_req->start_time, stop_time)); histogram_insert_data_point(write_req->dev->raw_write_hist, safe_delta_ns(raw_start_time, stop_time)); } }
//------------------------------------------------ // Do one device write operation. // static uint64_t write_to_device(device* dev, uint64_t offset, uint32_t size, const uint8_t* buf) { int fd = fd_get(dev); if (fd == -1) { return -1; } if (! pwrite_all(fd, buf, size, offset)) { close(fd); fprintf(stdout, "ERROR: writing %s: %d '%s'\n", dev->name, errno, act_strerror(errno)); return -1; } uint64_t stop_ns = get_ns(); fd_put(dev, fd); return stop_ns; }
static void *__ns_get_path(struct path *path, struct ns_common *ns) { struct vfsmount *mnt = nsfs_mnt; struct qstr qname = { .name = "", }; struct dentry *dentry; struct inode *inode; unsigned long d; rcu_read_lock(); d = atomic_long_read(&ns->stashed); if (!d) goto slow; dentry = (struct dentry *)d; if (!lockref_get_not_dead(&dentry->d_lockref)) goto slow; rcu_read_unlock(); ns->ops->put(ns); got_it: path->mnt = mntget(mnt); path->dentry = dentry; return NULL; slow: rcu_read_unlock(); inode = new_inode_pseudo(mnt->mnt_sb); if (!inode) { ns->ops->put(ns); return ERR_PTR(-ENOMEM); } inode->i_ino = ns->inum; inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); inode->i_flags |= S_IMMUTABLE; inode->i_mode = S_IFREG | S_IRUGO; inode->i_fop = &ns_file_operations; inode->i_private = ns; dentry = d_alloc_pseudo(mnt->mnt_sb, &qname); if (!dentry) { iput(inode); return ERR_PTR(-ENOMEM); } d_instantiate(dentry, inode); dentry->d_flags |= DCACHE_RCUACCESS; dentry->d_fsdata = (void *)ns->ops; d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); if (d) { d_delete(dentry); /* make sure ->d_prune() does nothing */ dput(dentry); cpu_relax(); return ERR_PTR(-EAGAIN); } goto got_it; } void *ns_get_path(struct path *path, struct task_struct *task, const struct proc_ns_operations *ns_ops) { struct ns_common *ns; void *ret; again: ns = ns_ops->get(task); if (!ns) return ERR_PTR(-ENOENT); ret = __ns_get_path(path, ns); if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN) goto again; return ret; } int open_related_ns(struct ns_common *ns, struct ns_common *(*get_ns)(struct ns_common *ns)) { struct path path = {}; struct file *f; void *err; int fd; fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) return fd; while (1) { struct ns_common *relative; relative = get_ns(ns); if (IS_ERR(relative)) { put_unused_fd(fd); return PTR_ERR(relative); } err = __ns_get_path(&path, relative); if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN) continue; break; } if (IS_ERR(err)) { put_unused_fd(fd); return PTR_ERR(err); } f = dentry_open(&path, O_RDONLY, current_cred()); path_put(&path); if (IS_ERR(f)) { put_unused_fd(fd); fd = PTR_ERR(f); } else fd_install(fd, f); return fd; } static long ns_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct user_namespace *user_ns; struct ns_common *ns = get_proc_ns(file_inode(filp)); uid_t __user *argp; uid_t uid; switch (ioctl) { case NS_GET_USERNS: return open_related_ns(ns, ns_get_owner); case NS_GET_PARENT: if (!ns->ops->get_parent) return -EINVAL; return open_related_ns(ns, ns->ops->get_parent); case NS_GET_NSTYPE: return ns->ops->type; case NS_GET_OWNER_UID: if (ns->ops->type != CLONE_NEWUSER) return -EINVAL; user_ns = container_of(ns, struct user_namespace, ns); argp = (uid_t __user *) arg; uid = from_kuid_munged(current_user_ns(), user_ns->owner); return put_user(uid, argp); default: return -ENOTTY; } } int ns_get_name(char *buf, size_t size, struct task_struct *task, const struct proc_ns_operations *ns_ops) { struct ns_common *ns; int res = -ENOENT; ns = ns_ops->get(task); if (ns) { res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum); ns_ops->put(ns); } return res; } struct file *proc_ns_fget(int fd) { struct file *file; file = fget(fd); if (!file) return ERR_PTR(-EBADF); if (file->f_op != &ns_file_operations) goto out_invalid; return file; out_invalid: fput(file); return ERR_PTR(-EINVAL); } static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry) { struct inode *inode = d_inode(dentry); const struct proc_ns_operations *ns_ops = dentry->d_fsdata; seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); return 0; } static const struct super_operations nsfs_ops = { .statfs = simple_statfs, .evict_inode = nsfs_evict, .show_path = nsfs_show_path, }; static struct dentry *nsfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_pseudo(fs_type, "nsfs:", &nsfs_ops, &ns_dentry_operations, NSFS_MAGIC); } static struct file_system_type nsfs = { .name = "nsfs", .mount = nsfs_mount, .kill_sb = kill_anon_super, }; void __init nsfs_init(void) { nsfs_mnt = kern_mount(&nsfs); if (IS_ERR(nsfs_mnt)) panic("can't set nsfs up\n"); nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; }
int main(int argc, char *argv[]) { int64_t time_start, time_end; g_thread_init(NULL); queue = g_async_queue_new(); lock = g_mutex_new(); cond_empty = g_cond_new(); cond_full = g_cond_new(); int opt; int backend = 0; while ((opt = getopt(argc, argv, "at:s:b:n:BFD")) != -1) { switch (opt) { case 'a': // Make BDB log writes more asynchronous opt_bdb_async = TRUE; break; case 't': // Set number of log worker threads opt_threads = atoi(optarg); break; case 's': // Set item size (in bytes) item_size = atoi(optarg); break; case 'b': // Set batch size opt_batchsize = atoi(optarg); break; case 'n': // Set object count opt_writes = atoi(optarg); break; case 'B': // Select BDB backend backend = 'b'; break; case 'F': // Select flat file backend backend = 'f'; break; case 'D': // Select file system directory backend backend = 'd'; break; default: /* '?' */ fprintf(stderr, "Usage: %s [-t threads] {-B|-F|-D}\n", argv[0]); return EXIT_FAILURE; } } switch (backend) { case 'b': launch_bdb(); break; case 'f': launch_flatlog(); break; case 'd': launch_fslog(); break; default: fprintf(stderr, "Backend not selected!\n"); return EXIT_FAILURE; } time_start = get_ns(); for (int i = 0; i < opt_writes; i++) { struct item *item = g_new(struct item, 1); item->key = g_strdup_printf("item-%06d", i); item->data = g_malloc(item_size); item->len = item_size; g_mutex_lock(lock); g_async_queue_push(queue, item); outstanding++; if (outstanding == opt_batchsize) g_cond_wait(cond_empty, lock); g_mutex_unlock(lock); } g_mutex_lock(lock); while (outstanding > 0) g_cond_wait(cond_empty, lock); g_mutex_unlock(lock); time_end = get_ns(); double elapsed = (time_end - time_start) / 1e9; printf("Elapsed: %f s\nThroughput: %f txn/s, %f MiB/s\n", elapsed, opt_writes / elapsed, opt_writes / elapsed * item_size / (1 << 20)); if (backend == 'b' && opt_bdb_async) backend = 'B'; FILE *f = fopen("../logbench.data", "a"); g_assert(f != NULL); fprintf(f, "%c\t%d\t%d\t%d\t%f\t%f\t%f\n", backend, item_size, opt_writes, opt_batchsize, elapsed, opt_writes / elapsed, opt_writes / elapsed * item_size / (1 << 20)); fclose(f); return 0; }
//------------------------------------------------ // Runs in service threads, adds read trans_req // objects to transaction queues in round-robin // fashion. // static void* run_generate_read_reqs(void* pv_unused) { rand_seed_thread(); uint64_t count = 0; uint64_t internal_read_reqs_per_sec = g_scfg.internal_read_reqs_per_sec / g_scfg.read_req_threads; while (g_running) { if (atomic32_incr(&g_reqs_queued) > g_scfg.max_reqs_queued) { fprintf(stdout, "ERROR: too many requests queued\n"); fprintf(stdout, "drive(s) can't keep up - test stopped\n"); g_running = false; break; } uint32_t q_index = count % g_scfg.num_queues; uint32_t random_dev_index = rand_32() % g_scfg.num_devices; device* random_dev = &g_devices[random_dev_index]; trans_req read_req = { .dev = random_dev, .offset = random_read_offset(random_dev), .size = random_read_size(random_dev), .is_write = false, .start_time = get_ns() }; queue_push(g_trans_qs[q_index], &read_req); count++; int64_t sleep_us = (int64_t) (((count * 1000000) / internal_read_reqs_per_sec) - (get_us() - g_run_start_us)); if (sleep_us > 0) { usleep((uint32_t)sleep_us); } else if (sleep_us < -(int64_t)g_scfg.max_lag_usec) { fprintf(stdout, "ERROR: read request generator can't keep up\n"); fprintf(stdout, "ACT can't do requested load - test stopped\n"); g_running = false; } } return NULL; } //------------------------------------------------ // Runs in service threads, adds write trans_req // objects to transaction queues in round-robin // fashion. // static void* run_generate_write_reqs(void* pv_unused) { rand_seed_thread(); uint64_t count = 0; uint64_t internal_write_reqs_per_sec = g_scfg.internal_write_reqs_per_sec / g_scfg.write_req_threads; while (g_running) { if (atomic32_incr(&g_reqs_queued) > g_scfg.max_reqs_queued) { fprintf(stdout, "ERROR: too many requests queued\n"); fprintf(stdout, "drive(s) can't keep up - test stopped\n"); g_running = false; break; } uint32_t q_index = count % g_scfg.num_queues; uint32_t random_dev_index = rand_32() % g_scfg.num_devices; device* random_dev = &g_devices[random_dev_index]; trans_req write_req = { .dev = random_dev, .offset = random_write_offset(random_dev), .size = random_write_size(random_dev), .is_write = true, .start_time = get_ns() }; queue_push(g_trans_qs[q_index], &write_req); count++; int64_t sleep_us = (int64_t) (((count * 1000000) / internal_write_reqs_per_sec) - (get_us() - g_run_start_us)); if (sleep_us > 0) { usleep((uint32_t)sleep_us); } else if (sleep_us < -(int64_t)g_scfg.max_lag_usec) { fprintf(stdout, "ERROR: write request generator can't keep up\n"); fprintf(stdout, "ACT can't do requested load - test stopped\n"); g_running = false; } } return NULL; } //------------------------------------------------ // Runs in every device large-block read thread, // executes large-block reads at a constant rate. // static void* run_large_block_reads(void* pv_dev) { rand_seed_thread(); device* dev = (device*)pv_dev; uint8_t* buf = act_valloc(g_scfg.large_block_ops_bytes); if (! buf) { fprintf(stdout, "ERROR: large block read buffer act_valloc()\n"); g_running = false; return NULL; } uint64_t count = 0; while (g_running) { read_and_report_large_block(dev, buf); count++; uint64_t target_us = (uint64_t) ((double)(count * 1000000 * g_scfg.num_devices) / g_scfg.large_block_reads_per_sec); int64_t sleep_us = (int64_t)(target_us - (get_us() - g_run_start_us)); if (sleep_us > 0) { usleep((uint32_t)sleep_us); } else if (sleep_us < -(int64_t)g_scfg.max_lag_usec) { fprintf(stdout, "ERROR: large block reads can't keep up\n"); fprintf(stdout, "drive(s) can't keep up - test stopped\n"); g_running = false; } } free(buf); return NULL; }
/*ARGSUSED*/ int nss_getpwnam(char *name, attrlist *items, pwu_repository_t *rep, void **buf) { attrlist *p; struct pwbuf *pwbuf; int repositories = REP_ERANGE; /* changed if ATTR_REP_NAME is set */ int err = PWU_SUCCESS; *buf = calloc(1, sizeof (struct pwbuf)); pwbuf = (struct pwbuf *)*buf; /* * determine which password structure (/etc/passwd or /etc/shadow) * we need for the items we need to update */ for (p = items; p != NULL; p = p->next) { switch (p->type) { case ATTR_NAME: case ATTR_UID: case ATTR_GID: case ATTR_AGE: case ATTR_COMMENT: case ATTR_GECOS: case ATTR_HOMEDIR: case ATTR_SHELL: if (pwbuf->pwd == NULL) pwbuf->pwd = (struct passwd *) malloc(sizeof (struct passwd)); if (pwbuf->pwd == NULL) { errno = ENOMEM; if (pwbuf->spwd) free(pwbuf->spwd); return (PWU_NOMEM); } break; case ATTR_PASSWD: case ATTR_PASSWD_SERVER_POLICY: case ATTR_LSTCHG: case ATTR_MIN: case ATTR_MAX: case ATTR_WARN: case ATTR_INACT: case ATTR_EXPIRE: case ATTR_FLAG: case ATTR_LOCK_ACCOUNT: case ATTR_EXPIRE_PASSWORD: case ATTR_FAILED_LOGINS: if (pwbuf->spwd == NULL) pwbuf->spwd = (struct spwd *) malloc(sizeof (struct spwd)); if (pwbuf->spwd == NULL) { errno = ENOMEM; if (pwbuf->pwd) free(pwbuf->pwd); return (PWU_NOMEM); } break; case ATTR_REP_NAME: /* get the compat names (REP_COMPAT_*) */ repositories = get_ns(rep, PWU_READ); break; default: /* * Some other repository might have different values * so we ignore those. */ break; } } if (pwbuf->pwd) { if ((pwbuf->pwd_scratch = malloc(PWD_SCRATCH_SIZE)) == NULL) { err = PWU_NOMEM; goto error; } if (getpwnam_r(name, pwbuf->pwd, pwbuf->pwd_scratch, PWD_SCRATCH_SIZE) == NULL) { err = PWU_NOT_FOUND; goto error; } } if (pwbuf->spwd) { if ((pwbuf->spwd_scratch = malloc(SPW_SCRATCH_SIZE)) == NULL) { err = PWU_NOMEM; goto error; } if (getspnam_r(name, pwbuf->spwd, pwbuf->spwd_scratch, SPW_SCRATCH_SIZE) == NULL) { err = PWU_NOT_FOUND; goto error; } } /* pwbuf->rep_name tells us where the user in fact comes from */ if (repositories != REP_ERANGE) { struct passwd pwd; char pwd_scratch[PWD_SCRATCH_SIZE]; /* can we find the user locally? */ if (private_getpwnam_r(name, &pwd, pwd_scratch, PWD_SCRATCH_SIZE) != NULL) pwbuf->rep_name = "files"; else if (repositories & REP_COMPAT_NISPLUS) pwbuf->rep_name = "nisplus"; else if (repositories & REP_COMPAT_LDAP) pwbuf->rep_name = "ldap"; else if (repositories & REP_COMPAT_NIS) pwbuf->rep_name = "nis"; else pwbuf->rep_name = "nss"; } else pwbuf->rep_name = "nss"; return (PWU_SUCCESS); error: if (pwbuf->pwd) free(pwbuf->pwd); if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch); if (pwbuf->spwd) free(pwbuf->spwd); if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch); free(pwbuf); *buf = NULL; return (err); }
void print_duration(struct timespec *start, struct timespec *end, long size) { long diff = get_ns(end) - get_ns(start); double tput = ((double)size / (double)(1000*1000)) / ( (double)diff / (double)(1000*1000*1000)); printf("Took %ld ns\n", diff); printf("Throughput (MB/s): %f\n", tput); }