From 575e946125f70c41c2042f10172842c5cab9a09a Mon Sep 17 00:00:00 2001 From: Mike Marshall Date: Fri, 4 Dec 2015 12:56:14 -0500 Subject: Orangefs: change pvfs2 filenames to orangefs Also changed references within source files that referred to header files whose names had changed. Signed-off-by: Mike Marshall --- Makefile | 2 +- fs/orangefs/Makefile | 8 +- fs/orangefs/acl.c | 4 +- fs/orangefs/dcache.c | 2 +- fs/orangefs/devorangefs-req.c | 984 +++++++++++++++++++++ fs/orangefs/devpvfs2-req.c | 984 --------------------- fs/orangefs/dir.c | 4 +- fs/orangefs/file.c | 6 +- fs/orangefs/inode.c | 8 +- fs/orangefs/namei.c | 2 +- fs/orangefs/orangefs-bufmap.c | 558 ++++++++++++ fs/orangefs/orangefs-bufmap.h | 62 ++ fs/orangefs/orangefs-cache.c | 246 ++++++ fs/orangefs/orangefs-debug.h | 292 +++++++ fs/orangefs/orangefs-debugfs.c | 458 ++++++++++ fs/orangefs/orangefs-debugfs.h | 3 + fs/orangefs/orangefs-dev-proto.h | 85 ++ fs/orangefs/orangefs-kernel.h | 819 +++++++++++++++++ fs/orangefs/orangefs-mod.c | 315 +++++++ fs/orangefs/orangefs-sysfs.c | 1787 ++++++++++++++++++++++++++++++++++++++ fs/orangefs/orangefs-sysfs.h | 2 + fs/orangefs/orangefs-utils.c | 1156 ++++++++++++++++++++++++ fs/orangefs/protocol.h | 6 +- fs/orangefs/pvfs2-bufmap.c | 558 ------------ fs/orangefs/pvfs2-bufmap.h | 62 -- fs/orangefs/pvfs2-cache.c | 246 ------ fs/orangefs/pvfs2-debug.h | 292 ------- fs/orangefs/pvfs2-debugfs.c | 458 ---------- fs/orangefs/pvfs2-debugfs.h | 3 - fs/orangefs/pvfs2-dev-proto.h | 85 -- fs/orangefs/pvfs2-kernel.h | 819 ----------------- fs/orangefs/pvfs2-mod.c | 315 ------- fs/orangefs/pvfs2-sysfs.c | 1787 -------------------------------------- fs/orangefs/pvfs2-sysfs.h | 2 - fs/orangefs/pvfs2-utils.c | 1156 ------------------------ fs/orangefs/super.c | 4 +- fs/orangefs/symlink.c | 4 +- fs/orangefs/waitqueue.c | 4 +- fs/orangefs/xattr.c | 4 +- 39 files changed, 6796 insertions(+), 6796 deletions(-) create mode 100644 fs/orangefs/devorangefs-req.c delete mode 100644 fs/orangefs/devpvfs2-req.c create mode 100644 fs/orangefs/orangefs-bufmap.c create mode 100644 fs/orangefs/orangefs-bufmap.h create mode 100644 fs/orangefs/orangefs-cache.c create mode 100644 fs/orangefs/orangefs-debug.h create mode 100644 fs/orangefs/orangefs-debugfs.c create mode 100644 fs/orangefs/orangefs-debugfs.h create mode 100644 fs/orangefs/orangefs-dev-proto.h create mode 100644 fs/orangefs/orangefs-kernel.h create mode 100644 fs/orangefs/orangefs-mod.c create mode 100644 fs/orangefs/orangefs-sysfs.c create mode 100644 fs/orangefs/orangefs-sysfs.h create mode 100644 fs/orangefs/orangefs-utils.c delete mode 100644 fs/orangefs/pvfs2-bufmap.c delete mode 100644 fs/orangefs/pvfs2-bufmap.h delete mode 100644 fs/orangefs/pvfs2-cache.c delete mode 100644 fs/orangefs/pvfs2-debug.h delete mode 100644 fs/orangefs/pvfs2-debugfs.c delete mode 100644 fs/orangefs/pvfs2-debugfs.h delete mode 100644 fs/orangefs/pvfs2-dev-proto.h delete mode 100644 fs/orangefs/pvfs2-kernel.h delete mode 100644 fs/orangefs/pvfs2-mod.c delete mode 100644 fs/orangefs/pvfs2-sysfs.c delete mode 100644 fs/orangefs/pvfs2-sysfs.h delete mode 100644 fs/orangefs/pvfs2-utils.c diff --git a/Makefile b/Makefile index 3a0234f50f36..aca4a73ad069 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc1-o NAME = Blurry Fish Butt # *DOCUMENTATION* diff --git a/fs/orangefs/Makefile b/fs/orangefs/Makefile index 828b36a6916d..a9d6a968fe6d 100644 --- a/fs/orangefs/Makefile +++ b/fs/orangefs/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_ORANGEFS_FS) += orangefs.o -orangefs-objs := acl.o file.o pvfs2-cache.o pvfs2-utils.o xattr.o dcache.o \ - inode.o pvfs2-sysfs.o pvfs2-mod.o super.o devpvfs2-req.o \ - namei.o symlink.o dir.o pvfs2-bufmap.o \ - pvfs2-debugfs.o waitqueue.o +orangefs-objs := acl.o file.o orangefs-cache.o orangefs-utils.o xattr.o \ + dcache.o inode.o orangefs-sysfs.o orangefs-mod.o super.o \ + devorangefs-req.o namei.o symlink.o dir.o orangefs-bufmap.o \ + orangefs-debugfs.o waitqueue.o diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c index 5e27d5fcb6bf..03f89dbb2512 100644 --- a/fs/orangefs/acl.c +++ b/fs/orangefs/acl.c @@ -5,8 +5,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" #include #include diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c index 12c916fa4c7f..5dd9841df64e 100644 --- a/fs/orangefs/dcache.c +++ b/fs/orangefs/dcache.c @@ -9,7 +9,7 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" +#include "orangefs-kernel.h" /* Returns 1 if dentry can still be trusted, else 0. */ static int orangefs_revalidate_lookup(struct dentry *dentry) diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c new file mode 100644 index 000000000000..e74938d575d6 --- /dev/null +++ b/fs/orangefs/devorangefs-req.c @@ -0,0 +1,984 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * Changes by Acxiom Corporation to add protocol version to kernel + * communication, Copyright Acxiom Corporation, 2005. + * + * See COPYING in top-level directory. + */ + +#include "protocol.h" +#include "orangefs-kernel.h" +#include "orangefs-dev-proto.h" +#include "orangefs-bufmap.h" + +#include +#include + +/* this file implements the /dev/pvfs2-req device node */ + +static int open_access_count; + +#define DUMP_DEVICE_ERROR() \ +do { \ + gossip_err("*****************************************************\n");\ + gossip_err("ORANGEFS Device Error: You cannot open the device file "); \ + gossip_err("\n/dev/%s more than once. Please make sure that\nthere " \ + "are no ", ORANGEFS_REQDEVICE_NAME); \ + gossip_err("instances of a program using this device\ncurrently " \ + "running. (You must verify this!)\n"); \ + gossip_err("For example, you can use the lsof program as follows:\n");\ + gossip_err("'lsof | grep %s' (run this as root)\n", \ + ORANGEFS_REQDEVICE_NAME); \ + gossip_err(" open_access_count = %d\n", open_access_count); \ + gossip_err("*****************************************************\n");\ +} while (0) + +static int hash_func(__u64 tag, int table_size) +{ + return do_div(tag, (unsigned int)table_size); +} + +static void orangefs_devreq_add_op(struct orangefs_kernel_op_s *op) +{ + int index = hash_func(op->tag, hash_table_size); + + spin_lock(&htable_ops_in_progress_lock); + list_add_tail(&op->list, &htable_ops_in_progress[index]); + spin_unlock(&htable_ops_in_progress_lock); +} + +static struct orangefs_kernel_op_s *orangefs_devreq_remove_op(__u64 tag) +{ + struct orangefs_kernel_op_s *op, *next; + int index; + + index = hash_func(tag, hash_table_size); + + spin_lock(&htable_ops_in_progress_lock); + list_for_each_entry_safe(op, + next, + &htable_ops_in_progress[index], + list) { + if (op->tag == tag) { + list_del(&op->list); + spin_unlock(&htable_ops_in_progress_lock); + return op; + } + } + + spin_unlock(&htable_ops_in_progress_lock); + return NULL; +} + +static int orangefs_devreq_open(struct inode *inode, struct file *file) +{ + int ret = -EINVAL; + + if (!(file->f_flags & O_NONBLOCK)) { + gossip_err("orangefs: device cannot be opened in blocking mode\n"); + goto out; + } + ret = -EACCES; + gossip_debug(GOSSIP_DEV_DEBUG, "pvfs2-client-core: opening device\n"); + mutex_lock(&devreq_mutex); + + if (open_access_count == 0) { + ret = generic_file_open(inode, file); + if (ret == 0) + open_access_count++; + } else { + DUMP_DEVICE_ERROR(); + } + mutex_unlock(&devreq_mutex); + +out: + + gossip_debug(GOSSIP_DEV_DEBUG, + "pvfs2-client-core: open device complete (ret = %d)\n", + ret); + return ret; +} + +static ssize_t orangefs_devreq_read(struct file *file, + char __user *buf, + size_t count, loff_t *offset) +{ + struct orangefs_kernel_op_s *op, *temp; + __s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION; + static __s32 magic = ORANGEFS_DEVREQ_MAGIC; + struct orangefs_kernel_op_s *cur_op = NULL; + unsigned long ret; + + /* We do not support blocking IO. */ + if (!(file->f_flags & O_NONBLOCK)) { + gossip_err("orangefs: blocking reads are not supported! (pvfs2-client-core bug)\n"); + return -EINVAL; + } + + /* + * The client will do an ioctl to find MAX_ALIGNED_DEV_REQ_UPSIZE, then + * always read with that size buffer. + */ + if (count != MAX_ALIGNED_DEV_REQ_UPSIZE) { + gossip_err("orangefs: client-core tried to read wrong size\n"); + return -EINVAL; + } + + /* Get next op (if any) from top of list. */ + spin_lock(&orangefs_request_list_lock); + list_for_each_entry_safe(op, temp, &orangefs_request_list, list) { + __s32 fsid; + /* This lock is held past the end of the loop when we break. */ + spin_lock(&op->lock); + + fsid = fsid_of_op(op); + if (fsid != ORANGEFS_FS_ID_NULL) { + int ret; + /* Skip ops whose filesystem needs to be mounted. */ + ret = fs_mount_pending(fsid); + if (ret == 1) { + gossip_debug(GOSSIP_DEV_DEBUG, + "orangefs: skipping op tag %llu %s\n", + llu(op->tag), get_opname_string(op)); + spin_unlock(&op->lock); + continue; + /* Skip ops whose filesystem we don't know about unless + * it is being mounted. */ + /* XXX: is there a better way to detect this? */ + } else if (ret == -1 && + !(op->upcall.type == ORANGEFS_VFS_OP_FS_MOUNT || + op->upcall.type == ORANGEFS_VFS_OP_GETATTR)) { + gossip_debug(GOSSIP_DEV_DEBUG, + "orangefs: skipping op tag %llu %s\n", + llu(op->tag), get_opname_string(op)); + gossip_err( + "orangefs: ERROR: fs_mount_pending %d\n", + fsid); + spin_unlock(&op->lock); + continue; + } + } + /* + * Either this op does not pertain to a filesystem, is mounting + * a filesystem, or pertains to a mounted filesystem. Let it + * through. + */ + cur_op = op; + break; + } + + /* + * At this point we either have a valid op and can continue or have not + * found an op and must ask the client to try again later. + */ + if (!cur_op) { + spin_unlock(&orangefs_request_list_lock); + return -EAGAIN; + } + + gossip_debug(GOSSIP_DEV_DEBUG, "orangefs: reading op tag %llu %s\n", + llu(cur_op->tag), get_opname_string(cur_op)); + + /* + * Such an op should never be on the list in the first place. If so, we + * will abort. + */ + if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) { + gossip_err("orangefs: ERROR: Current op already queued.\n"); + list_del(&cur_op->list); + spin_unlock(&cur_op->lock); + spin_unlock(&orangefs_request_list_lock); + return -EAGAIN; + } + + /* + * Set the operation to be in progress and move it between lists since + * it has been sent to the client. + */ + set_op_state_inprogress(cur_op); + + list_del(&cur_op->list); + spin_unlock(&orangefs_request_list_lock); + orangefs_devreq_add_op(cur_op); + spin_unlock(&cur_op->lock); + + /* Push the upcall out. */ + ret = copy_to_user(buf, &proto_ver, sizeof(__s32)); + if (ret != 0) + goto error; + ret = copy_to_user(buf+sizeof(__s32), &magic, sizeof(__s32)); + if (ret != 0) + goto error; + ret = copy_to_user(buf+2 * sizeof(__s32), &cur_op->tag, sizeof(__u64)); + if (ret != 0) + goto error; + ret = copy_to_user(buf+2*sizeof(__s32)+sizeof(__u64), &cur_op->upcall, + sizeof(struct orangefs_upcall_s)); + if (ret != 0) + goto error; + + /* The client only asks to read one size buffer. */ + return MAX_ALIGNED_DEV_REQ_UPSIZE; +error: + /* + * We were unable to copy the op data to the client. Put the op back in + * list. If client has crashed, the op will be purged later when the + * device is released. + */ + gossip_err("orangefs: Failed to copy data to user space\n"); + spin_lock(&orangefs_request_list_lock); + spin_lock(&cur_op->lock); + set_op_state_waiting(cur_op); + orangefs_devreq_remove_op(cur_op->tag); + list_add(&cur_op->list, &orangefs_request_list); + spin_unlock(&cur_op->lock); + spin_unlock(&orangefs_request_list_lock); + return -EFAULT; +} + +/* Function for writev() callers into the device */ +static ssize_t orangefs_devreq_writev(struct file *file, + const struct iovec *iov, + size_t count, + loff_t *offset) +{ + struct orangefs_kernel_op_s *op = NULL; + void *buffer = NULL; + void *ptr = NULL; + unsigned long i = 0; + static int max_downsize = MAX_ALIGNED_DEV_REQ_DOWNSIZE; + int ret = 0, num_remaining = max_downsize; + int notrailer_count = 4; /* num elements in iovec without trailer */ + int payload_size = 0; + __s32 magic = 0; + __s32 proto_ver = 0; + __u64 tag = 0; + ssize_t total_returned_size = 0; + + /* Either there is a trailer or there isn't */ + if (count != notrailer_count && count != (notrailer_count + 1)) { + gossip_err("Error: Number of iov vectors is (%zu) and notrailer count is %d\n", + count, + notrailer_count); + return -EPROTO; + } + buffer = dev_req_alloc(); + if (!buffer) + return -ENOMEM; + ptr = buffer; + + for (i = 0; i < notrailer_count; i++) { + if (iov[i].iov_len > num_remaining) { + gossip_err + ("writev error: Freeing buffer and returning\n"); + dev_req_release(buffer); + return -EMSGSIZE; + } + ret = copy_from_user(ptr, iov[i].iov_base, iov[i].iov_len); + if (ret) { + gossip_err("Failed to copy data from user space\n"); + dev_req_release(buffer); + return -EIO; + } + num_remaining -= iov[i].iov_len; + ptr += iov[i].iov_len; + payload_size += iov[i].iov_len; + } + total_returned_size = payload_size; + + /* these elements are currently 8 byte aligned (8 bytes for (version + + * magic) 8 bytes for tag). If you add another element, either + * make it 8 bytes big, or use get_unaligned when asigning. + */ + ptr = buffer; + proto_ver = *((__s32 *) ptr); + ptr += sizeof(__s32); + + magic = *((__s32 *) ptr); + ptr += sizeof(__s32); + + tag = *((__u64 *) ptr); + ptr += sizeof(__u64); + + if (magic != ORANGEFS_DEVREQ_MAGIC) { + gossip_err("Error: Device magic number does not match.\n"); + dev_req_release(buffer); + return -EPROTO; + } + + /* + * proto_ver = 20902 for 2.9.2 + */ + + op = orangefs_devreq_remove_op(tag); + if (op) { + /* Increase ref count! */ + get_op(op); + /* cut off magic and tag from payload size */ + payload_size -= (2 * sizeof(__s32) + sizeof(__u64)); + if (payload_size <= sizeof(struct orangefs_downcall_s)) + /* copy the passed in downcall into the op */ + memcpy(&op->downcall, + ptr, + sizeof(struct orangefs_downcall_s)); + else + gossip_debug(GOSSIP_DEV_DEBUG, + "writev: Ignoring %d bytes\n", + payload_size); + + /* Do not allocate needlessly if client-core forgets + * to reset trailer size on op errors. + */ + if (op->downcall.status == 0 && op->downcall.trailer_size > 0) { + __u64 trailer_size = op->downcall.trailer_size; + size_t size; + gossip_debug(GOSSIP_DEV_DEBUG, + "writev: trailer size %ld\n", + (unsigned long)trailer_size); + if (count != (notrailer_count + 1)) { + gossip_err("Error: trailer size (%ld) is non-zero, no trailer elements though? (%zu)\n", (unsigned long)trailer_size, count); + dev_req_release(buffer); + put_op(op); + return -EPROTO; + } + size = iov[notrailer_count].iov_len; + if (size > trailer_size) { + gossip_err("writev error: trailer size (%ld) != iov_len (%zd)\n", (unsigned long)trailer_size, size); + dev_req_release(buffer); + put_op(op); + return -EMSGSIZE; + } + /* Allocate a buffer large enough to hold the + * trailer bytes. + */ + op->downcall.trailer_buf = vmalloc(trailer_size); + if (op->downcall.trailer_buf != NULL) { + gossip_debug(GOSSIP_DEV_DEBUG, "vmalloc: %p\n", + op->downcall.trailer_buf); + ret = copy_from_user(op->downcall.trailer_buf, + iov[notrailer_count]. + iov_base, + size); + if (ret) { + gossip_err("Failed to copy trailer data from user space\n"); + dev_req_release(buffer); + gossip_debug(GOSSIP_DEV_DEBUG, + "vfree: %p\n", + op->downcall.trailer_buf); + vfree(op->downcall.trailer_buf); + op->downcall.trailer_buf = NULL; + put_op(op); + return -EIO; + } + memset(op->downcall.trailer_buf + size, 0, + trailer_size - size); + } else { + /* Change downcall status */ + op->downcall.status = -ENOMEM; + gossip_err("writev: could not vmalloc for trailer!\n"); + } + } + + /* if this operation is an I/O operation and if it was + * initiated on behalf of a *synchronous* VFS I/O operation, + * only then we need to wait + * for all data to be copied before we can return to avoid + * buffer corruption and races that can pull the buffers + * out from under us. + * + * Essentially we're synchronizing with other parts of the + * vfs implicitly by not allowing the user space + * application reading/writing this device to return until + * the buffers are done being used. + */ + if (op->upcall.type == ORANGEFS_VFS_OP_FILE_IO && + op->upcall.req.io.async_vfs_io == ORANGEFS_VFS_SYNC_IO) { + int timed_out = 0; + DECLARE_WAITQUEUE(wait_entry, current); + + /* tell the vfs op waiting on a waitqueue + * that this op is done + */ + spin_lock(&op->lock); + set_op_state_serviced(op); + spin_unlock(&op->lock); + + add_wait_queue_exclusive(&op->io_completion_waitq, + &wait_entry); + wake_up_interruptible(&op->waitq); + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock(&op->lock); + if (op->io_completed) { + spin_unlock(&op->lock); + break; + } + spin_unlock(&op->lock); + + if (!signal_pending(current)) { + int timeout = + MSECS_TO_JIFFIES(1000 * + op_timeout_secs); + if (!schedule_timeout(timeout)) { + gossip_debug(GOSSIP_DEV_DEBUG, "*** I/O wait time is up\n"); + timed_out = 1; + break; + } + continue; + } + + gossip_debug(GOSSIP_DEV_DEBUG, "*** signal on I/O wait -- aborting\n"); + break; + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&op->io_completion_waitq, + &wait_entry); + + /* NOTE: for I/O operations we handle releasing the op + * object except in the case of timeout. the reason we + * can't free the op in timeout cases is that the op + * service logic in the vfs retries operations using + * the same op ptr, thus it can't be freed. + */ + if (!timed_out) + op_release(op); + } else { + + /* + * tell the vfs op waiting on a waitqueue that + * this op is done + */ + spin_lock(&op->lock); + set_op_state_serviced(op); + spin_unlock(&op->lock); + /* + * for every other operation (i.e. non-I/O), we need to + * wake up the callers for downcall completion + * notification + */ + wake_up_interruptible(&op->waitq); + } + } else { + /* ignore downcalls that we're not interested in */ + gossip_debug(GOSSIP_DEV_DEBUG, + "WARNING: No one's waiting for tag %llu\n", + llu(tag)); + } + dev_req_release(buffer); + + return total_returned_size; +} + +static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, + struct iov_iter *iter) +{ + return orangefs_devreq_writev(iocb->ki_filp, + iter->iov, + iter->nr_segs, + &iocb->ki_pos); +} + +/* Returns whether any FS are still pending remounted */ +static int mark_all_pending_mounts(void) +{ + int unmounted = 1; + struct orangefs_sb_info_s *orangefs_sb = NULL; + + spin_lock(&orangefs_superblocks_lock); + list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) { + /* All of these file system require a remount */ + orangefs_sb->mount_pending = 1; + unmounted = 0; + } + spin_unlock(&orangefs_superblocks_lock); + return unmounted; +} + +/* + * Determine if a given file system needs to be remounted or not + * Returns -1 on error + * 0 if already mounted + * 1 if needs remount + */ +int fs_mount_pending(__s32 fsid) +{ + int mount_pending = -1; + struct orangefs_sb_info_s *orangefs_sb = NULL; + + spin_lock(&orangefs_superblocks_lock); + list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) { + if (orangefs_sb->fs_id == fsid) { + mount_pending = orangefs_sb->mount_pending; + break; + } + } + spin_unlock(&orangefs_superblocks_lock); + return mount_pending; +} + +/* + * NOTE: gets called when the last reference to this device is dropped. + * Using the open_access_count variable, we enforce a reference count + * on this file so that it can be opened by only one process at a time. + * the devreq_mutex is used to make sure all i/o has completed + * before we call orangefs_bufmap_finalize, and similar such tricky + * situations + */ +static int orangefs_devreq_release(struct inode *inode, struct file *file) +{ + int unmounted = 0; + + gossip_debug(GOSSIP_DEV_DEBUG, + "%s:pvfs2-client-core: exiting, closing device\n", + __func__); + + mutex_lock(&devreq_mutex); + orangefs_bufmap_finalize(); + + open_access_count--; + + unmounted = mark_all_pending_mounts(); + gossip_debug(GOSSIP_DEV_DEBUG, "ORANGEFS Device Close: Filesystem(s) %s\n", + (unmounted ? "UNMOUNTED" : "MOUNTED")); + mutex_unlock(&devreq_mutex); + + /* + * Walk through the list of ops in the request list, mark them + * as purged and wake them up. + */ + purge_waiting_ops(); + /* + * Walk through the hash table of in progress operations; mark + * them as purged and wake them up + */ + purge_inprogress_ops(); + gossip_debug(GOSSIP_DEV_DEBUG, + "pvfs2-client-core: device close complete\n"); + return 0; +} + +int is_daemon_in_service(void) +{ + int in_service; + + /* + * What this function does is checks if client-core is alive + * based on the access count we maintain on the device. + */ + mutex_lock(&devreq_mutex); + in_service = open_access_count == 1 ? 0 : -EIO; + mutex_unlock(&devreq_mutex); + return in_service; +} + +static inline long check_ioctl_command(unsigned int command) +{ + /* Check for valid ioctl codes */ + if (_IOC_TYPE(command) != ORANGEFS_DEV_MAGIC) { + gossip_err("device ioctl magic numbers don't match! Did you rebuild pvfs2-client-core/libpvfs2? [cmd %x, magic %x != %x]\n", + command, + _IOC_TYPE(command), + ORANGEFS_DEV_MAGIC); + return -EINVAL; + } + /* and valid ioctl commands */ + if (_IOC_NR(command) >= ORANGEFS_DEV_MAXNR || _IOC_NR(command) <= 0) { + gossip_err("Invalid ioctl command number [%d >= %d]\n", + _IOC_NR(command), ORANGEFS_DEV_MAXNR); + return -ENOIOCTLCMD; + } + return 0; +} + +static long dispatch_ioctl_command(unsigned int command, unsigned long arg) +{ + static __s32 magic = ORANGEFS_DEVREQ_MAGIC; + static __s32 max_up_size = MAX_ALIGNED_DEV_REQ_UPSIZE; + static __s32 max_down_size = MAX_ALIGNED_DEV_REQ_DOWNSIZE; + struct ORANGEFS_dev_map_desc user_desc; + int ret = 0; + struct dev_mask_info_s mask_info = { 0 }; + struct dev_mask2_info_s mask2_info = { 0, 0 }; + int upstream_kmod = 1; + struct list_head *tmp = NULL; + struct orangefs_sb_info_s *orangefs_sb = NULL; + + /* mtmoore: add locking here */ + + switch (command) { + case ORANGEFS_DEV_GET_MAGIC: + return ((put_user(magic, (__s32 __user *) arg) == -EFAULT) ? + -EIO : + 0); + case ORANGEFS_DEV_GET_MAX_UPSIZE: + return ((put_user(max_up_size, + (__s32 __user *) arg) == -EFAULT) ? + -EIO : + 0); + case ORANGEFS_DEV_GET_MAX_DOWNSIZE: + return ((put_user(max_down_size, + (__s32 __user *) arg) == -EFAULT) ? + -EIO : + 0); + case ORANGEFS_DEV_MAP: + ret = copy_from_user(&user_desc, + (struct ORANGEFS_dev_map_desc __user *) + arg, + sizeof(struct ORANGEFS_dev_map_desc)); + return ret ? -EIO : orangefs_bufmap_initialize(&user_desc); + case ORANGEFS_DEV_REMOUNT_ALL: + gossip_debug(GOSSIP_DEV_DEBUG, + "orangefs_devreq_ioctl: got ORANGEFS_DEV_REMOUNT_ALL\n"); + + /* + * remount all mounted orangefs volumes to regain the lost + * dynamic mount tables (if any) -- NOTE: this is done + * without keeping the superblock list locked due to the + * upcall/downcall waiting. also, the request semaphore is + * used to ensure that no operations will be serviced until + * all of the remounts are serviced (to avoid ops between + * mounts to fail) + */ + ret = mutex_lock_interruptible(&request_mutex); + if (ret < 0) + return ret; + gossip_debug(GOSSIP_DEV_DEBUG, + "orangefs_devreq_ioctl: priority remount in progress\n"); + list_for_each(tmp, &orangefs_superblocks) { + orangefs_sb = + list_entry(tmp, struct orangefs_sb_info_s, list); + if (orangefs_sb && (orangefs_sb->sb)) { + gossip_debug(GOSSIP_DEV_DEBUG, + "Remounting SB %p\n", + orangefs_sb); + + ret = orangefs_remount(orangefs_sb->sb); + if (ret) { + gossip_debug(GOSSIP_DEV_DEBUG, + "SB %p remount failed\n", + orangefs_sb); + break; + } + } + } + gossip_debug(GOSSIP_DEV_DEBUG, + "orangefs_devreq_ioctl: priority remount complete\n"); + mutex_unlock(&request_mutex); + return ret; + + case ORANGEFS_DEV_UPSTREAM: + ret = copy_to_user((void __user *)arg, + &upstream_kmod, + sizeof(upstream_kmod)); + + if (ret != 0) + return -EIO; + else + return ret; + + case ORANGEFS_DEV_CLIENT_MASK: + ret = copy_from_user(&mask2_info, + (void __user *)arg, + sizeof(struct dev_mask2_info_s)); + + if (ret != 0) + return -EIO; + + client_debug_mask.mask1 = mask2_info.mask1_value; + client_debug_mask.mask2 = mask2_info.mask2_value; + + pr_info("%s: client debug mask has been been received " + ":%llx: :%llx:\n", + __func__, + (unsigned long long)client_debug_mask.mask1, + (unsigned long long)client_debug_mask.mask2); + + return ret; + + case ORANGEFS_DEV_CLIENT_STRING: + ret = copy_from_user(&client_debug_array_string, + (void __user *)arg, + ORANGEFS_MAX_DEBUG_STRING_LEN); + if (ret != 0) { + pr_info("%s: " + "ORANGEFS_DEV_CLIENT_STRING: copy_from_user failed" + "\n", + __func__); + return -EIO; + } + + pr_info("%s: client debug array string has been been received." + "\n", + __func__); + + if (!help_string_initialized) { + + /* Free the "we don't know yet" default string... */ + kfree(debug_help_string); + + /* build a proper debug help string */ + if (orangefs_prepare_debugfs_help_string(0)) { + gossip_err("%s: " + "prepare_debugfs_help_string failed" + "\n", + __func__); + return -EIO; + } + + /* Replace the boilerplate boot-time debug-help file. */ + debugfs_remove(help_file_dentry); + + help_file_dentry = + debugfs_create_file( + ORANGEFS_KMOD_DEBUG_HELP_FILE, + 0444, + debug_dir, + debug_help_string, + &debug_help_fops); + + if (!help_file_dentry) { + gossip_err("%s: debugfs_create_file failed for" + " :%s:!\n", + __func__, + ORANGEFS_KMOD_DEBUG_HELP_FILE); + return -EIO; + } + } + + debug_mask_to_string(&client_debug_mask, 1); + + debugfs_remove(client_debug_dentry); + + orangefs_client_debug_init(); + + help_string_initialized++; + + return ret; + + case ORANGEFS_DEV_DEBUG: + ret = copy_from_user(&mask_info, + (void __user *)arg, + sizeof(mask_info)); + + if (ret != 0) + return -EIO; + + if (mask_info.mask_type == KERNEL_MASK) { + if ((mask_info.mask_value == 0) + && (kernel_mask_set_mod_init)) { + /* + * the kernel debug mask was set when the + * kernel module was loaded; don't override + * it if the client-core was started without + * a value for ORANGEFS_KMODMASK. + */ + return 0; + } + debug_mask_to_string(&mask_info.mask_value, + mask_info.mask_type); + gossip_debug_mask = mask_info.mask_value; + pr_info("ORANGEFS: kernel debug mask has been modified to " + ":%s: :%llx:\n", + kernel_debug_string, + (unsigned long long)gossip_debug_mask); + } else if (mask_info.mask_type == CLIENT_MASK) { + debug_mask_to_string(&mask_info.mask_value, + mask_info.mask_type); + pr_info("ORANGEFS: client debug mask has been modified to" + ":%s: :%llx:\n", + client_debug_string, + llu(mask_info.mask_value)); + } else { + gossip_lerr("Invalid mask type....\n"); + return -EINVAL; + } + + return ret; + + default: + return -ENOIOCTLCMD; + } + return -ENOIOCTLCMD; +} + +static long orangefs_devreq_ioctl(struct file *file, + unsigned int command, unsigned long arg) +{ + long ret; + + /* Check for properly constructed commands */ + ret = check_ioctl_command(command); + if (ret < 0) + return (int)ret; + + return (int)dispatch_ioctl_command(command, arg); +} + +#ifdef CONFIG_COMPAT /* CONFIG_COMPAT is in .config */ + +/* Compat structure for the ORANGEFS_DEV_MAP ioctl */ +struct ORANGEFS_dev_map_desc32 { + compat_uptr_t ptr; + __s32 total_size; + __s32 size; + __s32 count; +}; + +static unsigned long translate_dev_map26(unsigned long args, long *error) +{ + struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args; + /* + * Depending on the architecture, allocate some space on the + * user-call-stack based on our expected layout. + */ + struct ORANGEFS_dev_map_desc __user *p = + compat_alloc_user_space(sizeof(*p)); + compat_uptr_t addr; + + *error = 0; + /* get the ptr from the 32 bit user-space */ + if (get_user(addr, &p32->ptr)) + goto err; + /* try to put that into a 64-bit layout */ + if (put_user(compat_ptr(addr), &p->ptr)) + goto err; + /* copy the remaining fields */ + if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32))) + goto err; + if (copy_in_user(&p->size, &p32->size, sizeof(__s32))) + goto err; + if (copy_in_user(&p->count, &p32->count, sizeof(__s32))) + goto err; + return (unsigned long)p; +err: + *error = -EFAULT; + return 0; +} + +/* + * 32 bit user-space apps' ioctl handlers when kernel modules + * is compiled as a 64 bit one + */ +static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long args) +{ + long ret; + unsigned long arg = args; + + /* Check for properly constructed commands */ + ret = check_ioctl_command(cmd); + if (ret < 0) + return ret; + if (cmd == ORANGEFS_DEV_MAP) { + /* + * convert the arguments to what we expect internally + * in kernel space + */ + arg = translate_dev_map26(args, &ret); + if (ret < 0) { + gossip_err("Could not translate dev map\n"); + return ret; + } + } + /* no other ioctl requires translation */ + return dispatch_ioctl_command(cmd, arg); +} + +#endif /* CONFIG_COMPAT is in .config */ + +/* + * The following two ioctl32 functions had been refactored into the above + * CONFIG_COMPAT ifdef, but that was an over simplification that was + * not noticed until we tried to compile on power pc... + */ +#if (defined(CONFIG_COMPAT) && !defined(HAVE_REGISTER_IOCTL32_CONVERSION)) || !defined(CONFIG_COMPAT) +static int orangefs_ioctl32_init(void) +{ + return 0; +} + +static void orangefs_ioctl32_cleanup(void) +{ + return; +} +#endif + +/* the assigned character device major number */ +static int orangefs_dev_major; + +/* + * Initialize orangefs device specific state: + * Must be called at module load time only + */ +int orangefs_dev_init(void) +{ + int ret; + + /* register the ioctl32 sub-system */ + ret = orangefs_ioctl32_init(); + if (ret < 0) + return ret; + + /* register orangefs-req device */ + orangefs_dev_major = register_chrdev(0, + ORANGEFS_REQDEVICE_NAME, + &orangefs_devreq_file_operations); + if (orangefs_dev_major < 0) { + gossip_debug(GOSSIP_DEV_DEBUG, + "Failed to register /dev/%s (error %d)\n", + ORANGEFS_REQDEVICE_NAME, orangefs_dev_major); + orangefs_ioctl32_cleanup(); + return orangefs_dev_major; + } + + gossip_debug(GOSSIP_DEV_DEBUG, + "*** /dev/%s character device registered ***\n", + ORANGEFS_REQDEVICE_NAME); + gossip_debug(GOSSIP_DEV_DEBUG, "'mknod /dev/%s c %d 0'.\n", + ORANGEFS_REQDEVICE_NAME, orangefs_dev_major); + return 0; +} + +void orangefs_dev_cleanup(void) +{ + unregister_chrdev(orangefs_dev_major, ORANGEFS_REQDEVICE_NAME); + gossip_debug(GOSSIP_DEV_DEBUG, + "*** /dev/%s character device unregistered ***\n", + ORANGEFS_REQDEVICE_NAME); + /* unregister the ioctl32 sub-system */ + orangefs_ioctl32_cleanup(); +} + +static unsigned int orangefs_devreq_poll(struct file *file, + struct poll_table_struct *poll_table) +{ + int poll_revent_mask = 0; + + if (open_access_count == 1) { + poll_wait(file, &orangefs_request_list_waitq, poll_table); + + spin_lock(&orangefs_request_list_lock); + if (!list_empty(&orangefs_request_list)) + poll_revent_mask |= POLL_IN; + spin_unlock(&orangefs_request_list_lock); + } + return poll_revent_mask; +} + +const struct file_operations orangefs_devreq_file_operations = { + .owner = THIS_MODULE, + .read = orangefs_devreq_read, + .write_iter = orangefs_devreq_write_iter, + .open = orangefs_devreq_open, + .release = orangefs_devreq_release, + .unlocked_ioctl = orangefs_devreq_ioctl, + +#ifdef CONFIG_COMPAT /* CONFIG_COMPAT is in .config */ + .compat_ioctl = orangefs_devreq_compat_ioctl, +#endif + .poll = orangefs_devreq_poll +}; diff --git a/fs/orangefs/devpvfs2-req.c b/fs/orangefs/devpvfs2-req.c deleted file mode 100644 index e18149f0975b..000000000000 --- a/fs/orangefs/devpvfs2-req.c +++ /dev/null @@ -1,984 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * Changes by Acxiom Corporation to add protocol version to kernel - * communication, Copyright Acxiom Corporation, 2005. - * - * See COPYING in top-level directory. - */ - -#include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-dev-proto.h" -#include "pvfs2-bufmap.h" - -#include -#include - -/* this file implements the /dev/pvfs2-req device node */ - -static int open_access_count; - -#define DUMP_DEVICE_ERROR() \ -do { \ - gossip_err("*****************************************************\n");\ - gossip_err("ORANGEFS Device Error: You cannot open the device file "); \ - gossip_err("\n/dev/%s more than once. Please make sure that\nthere " \ - "are no ", ORANGEFS_REQDEVICE_NAME); \ - gossip_err("instances of a program using this device\ncurrently " \ - "running. (You must verify this!)\n"); \ - gossip_err("For example, you can use the lsof program as follows:\n");\ - gossip_err("'lsof | grep %s' (run this as root)\n", \ - ORANGEFS_REQDEVICE_NAME); \ - gossip_err(" open_access_count = %d\n", open_access_count); \ - gossip_err("*****************************************************\n");\ -} while (0) - -static int hash_func(__u64 tag, int table_size) -{ - return do_div(tag, (unsigned int)table_size); -} - -static void orangefs_devreq_add_op(struct orangefs_kernel_op_s *op) -{ - int index = hash_func(op->tag, hash_table_size); - - spin_lock(&htable_ops_in_progress_lock); - list_add_tail(&op->list, &htable_ops_in_progress[index]); - spin_unlock(&htable_ops_in_progress_lock); -} - -static struct orangefs_kernel_op_s *orangefs_devreq_remove_op(__u64 tag) -{ - struct orangefs_kernel_op_s *op, *next; - int index; - - index = hash_func(tag, hash_table_size); - - spin_lock(&htable_ops_in_progress_lock); - list_for_each_entry_safe(op, - next, - &htable_ops_in_progress[index], - list) { - if (op->tag == tag) { - list_del(&op->list); - spin_unlock(&htable_ops_in_progress_lock); - return op; - } - } - - spin_unlock(&htable_ops_in_progress_lock); - return NULL; -} - -static int orangefs_devreq_open(struct inode *inode, struct file *file) -{ - int ret = -EINVAL; - - if (!(file->f_flags & O_NONBLOCK)) { - gossip_err("orangefs: device cannot be opened in blocking mode\n"); - goto out; - } - ret = -EACCES; - gossip_debug(GOSSIP_DEV_DEBUG, "pvfs2-client-core: opening device\n"); - mutex_lock(&devreq_mutex); - - if (open_access_count == 0) { - ret = generic_file_open(inode, file); - if (ret == 0) - open_access_count++; - } else { - DUMP_DEVICE_ERROR(); - } - mutex_unlock(&devreq_mutex); - -out: - - gossip_debug(GOSSIP_DEV_DEBUG, - "pvfs2-client-core: open device complete (ret = %d)\n", - ret); - return ret; -} - -static ssize_t orangefs_devreq_read(struct file *file, - char __user *buf, - size_t count, loff_t *offset) -{ - struct orangefs_kernel_op_s *op, *temp; - __s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION; - static __s32 magic = ORANGEFS_DEVREQ_MAGIC; - struct orangefs_kernel_op_s *cur_op = NULL; - unsigned long ret; - - /* We do not support blocking IO. */ - if (!(file->f_flags & O_NONBLOCK)) { - gossip_err("orangefs: blocking reads are not supported! (pvfs2-client-core bug)\n"); - return -EINVAL; - } - - /* - * The client will do an ioctl to find MAX_ALIGNED_DEV_REQ_UPSIZE, then - * always read with that size buffer. - */ - if (count != MAX_ALIGNED_DEV_REQ_UPSIZE) { - gossip_err("orangefs: client-core tried to read wrong size\n"); - return -EINVAL; - } - - /* Get next op (if any) from top of list. */ - spin_lock(&orangefs_request_list_lock); - list_for_each_entry_safe(op, temp, &orangefs_request_list, list) { - __s32 fsid; - /* This lock is held past the end of the loop when we break. */ - spin_lock(&op->lock); - - fsid = fsid_of_op(op); - if (fsid != ORANGEFS_FS_ID_NULL) { - int ret; - /* Skip ops whose filesystem needs to be mounted. */ - ret = fs_mount_pending(fsid); - if (ret == 1) { - gossip_debug(GOSSIP_DEV_DEBUG, - "orangefs: skipping op tag %llu %s\n", - llu(op->tag), get_opname_string(op)); - spin_unlock(&op->lock); - continue; - /* Skip ops whose filesystem we don't know about unless - * it is being mounted. */ - /* XXX: is there a better way to detect this? */ - } else if (ret == -1 && - !(op->upcall.type == ORANGEFS_VFS_OP_FS_MOUNT || - op->upcall.type == ORANGEFS_VFS_OP_GETATTR)) { - gossip_debug(GOSSIP_DEV_DEBUG, - "orangefs: skipping op tag %llu %s\n", - llu(op->tag), get_opname_string(op)); - gossip_err( - "orangefs: ERROR: fs_mount_pending %d\n", - fsid); - spin_unlock(&op->lock); - continue; - } - } - /* - * Either this op does not pertain to a filesystem, is mounting - * a filesystem, or pertains to a mounted filesystem. Let it - * through. - */ - cur_op = op; - break; - } - - /* - * At this point we either have a valid op and can continue or have not - * found an op and must ask the client to try again later. - */ - if (!cur_op) { - spin_unlock(&orangefs_request_list_lock); - return -EAGAIN; - } - - gossip_debug(GOSSIP_DEV_DEBUG, "orangefs: reading op tag %llu %s\n", - llu(cur_op->tag), get_opname_string(cur_op)); - - /* - * Such an op should never be on the list in the first place. If so, we - * will abort. - */ - if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) { - gossip_err("orangefs: ERROR: Current op already queued.\n"); - list_del(&cur_op->list); - spin_unlock(&cur_op->lock); - spin_unlock(&orangefs_request_list_lock); - return -EAGAIN; - } - - /* - * Set the operation to be in progress and move it between lists since - * it has been sent to the client. - */ - set_op_state_inprogress(cur_op); - - list_del(&cur_op->list); - spin_unlock(&orangefs_request_list_lock); - orangefs_devreq_add_op(cur_op); - spin_unlock(&cur_op->lock); - - /* Push the upcall out. */ - ret = copy_to_user(buf, &proto_ver, sizeof(__s32)); - if (ret != 0) - goto error; - ret = copy_to_user(buf+sizeof(__s32), &magic, sizeof(__s32)); - if (ret != 0) - goto error; - ret = copy_to_user(buf+2 * sizeof(__s32), &cur_op->tag, sizeof(__u64)); - if (ret != 0) - goto error; - ret = copy_to_user(buf+2*sizeof(__s32)+sizeof(__u64), &cur_op->upcall, - sizeof(struct orangefs_upcall_s)); - if (ret != 0) - goto error; - - /* The client only asks to read one size buffer. */ - return MAX_ALIGNED_DEV_REQ_UPSIZE; -error: - /* - * We were unable to copy the op data to the client. Put the op back in - * list. If client has crashed, the op will be purged later when the - * device is released. - */ - gossip_err("orangefs: Failed to copy data to user space\n"); - spin_lock(&orangefs_request_list_lock); - spin_lock(&cur_op->lock); - set_op_state_waiting(cur_op); - orangefs_devreq_remove_op(cur_op->tag); - list_add(&cur_op->list, &orangefs_request_list); - spin_unlock(&cur_op->lock); - spin_unlock(&orangefs_request_list_lock); - return -EFAULT; -} - -/* Function for writev() callers into the device */ -static ssize_t orangefs_devreq_writev(struct file *file, - const struct iovec *iov, - size_t count, - loff_t *offset) -{ - struct orangefs_kernel_op_s *op = NULL; - void *buffer = NULL; - void *ptr = NULL; - unsigned long i = 0; - static int max_downsize = MAX_ALIGNED_DEV_REQ_DOWNSIZE; - int ret = 0, num_remaining = max_downsize; - int notrailer_count = 4; /* num elements in iovec without trailer */ - int payload_size = 0; - __s32 magic = 0; - __s32 proto_ver = 0; - __u64 tag = 0; - ssize_t total_returned_size = 0; - - /* Either there is a trailer or there isn't */ - if (count != notrailer_count && count != (notrailer_count + 1)) { - gossip_err("Error: Number of iov vectors is (%zu) and notrailer count is %d\n", - count, - notrailer_count); - return -EPROTO; - } - buffer = dev_req_alloc(); - if (!buffer) - return -ENOMEM; - ptr = buffer; - - for (i = 0; i < notrailer_count; i++) { - if (iov[i].iov_len > num_remaining) { - gossip_err - ("writev error: Freeing buffer and returning\n"); - dev_req_release(buffer); - return -EMSGSIZE; - } - ret = copy_from_user(ptr, iov[i].iov_base, iov[i].iov_len); - if (ret) { - gossip_err("Failed to copy data from user space\n"); - dev_req_release(buffer); - return -EIO; - } - num_remaining -= iov[i].iov_len; - ptr += iov[i].iov_len; - payload_size += iov[i].iov_len; - } - total_returned_size = payload_size; - - /* these elements are currently 8 byte aligned (8 bytes for (version + - * magic) 8 bytes for tag). If you add another element, either - * make it 8 bytes big, or use get_unaligned when asigning. - */ - ptr = buffer; - proto_ver = *((__s32 *) ptr); - ptr += sizeof(__s32); - - magic = *((__s32 *) ptr); - ptr += sizeof(__s32); - - tag = *((__u64 *) ptr); - ptr += sizeof(__u64); - - if (magic != ORANGEFS_DEVREQ_MAGIC) { - gossip_err("Error: Device magic number does not match.\n"); - dev_req_release(buffer); - return -EPROTO; - } - - /* - * proto_ver = 20902 for 2.9.2 - */ - - op = orangefs_devreq_remove_op(tag); - if (op) { - /* Increase ref count! */ - get_op(op); - /* cut off magic and tag from payload size */ - payload_size -= (2 * sizeof(__s32) + sizeof(__u64)); - if (payload_size <= sizeof(struct orangefs_downcall_s)) - /* copy the passed in downcall into the op */ - memcpy(&op->downcall, - ptr, - sizeof(struct orangefs_downcall_s)); - else - gossip_debug(GOSSIP_DEV_DEBUG, - "writev: Ignoring %d bytes\n", - payload_size); - - /* Do not allocate needlessly if client-core forgets - * to reset trailer size on op errors. - */ - if (op->downcall.status == 0 && op->downcall.trailer_size > 0) { - __u64 trailer_size = op->downcall.trailer_size; - size_t size; - gossip_debug(GOSSIP_DEV_DEBUG, - "writev: trailer size %ld\n", - (unsigned long)trailer_size); - if (count != (notrailer_count + 1)) { - gossip_err("Error: trailer size (%ld) is non-zero, no trailer elements though? (%zu)\n", (unsigned long)trailer_size, count); - dev_req_release(buffer); - put_op(op); - return -EPROTO; - } - size = iov[notrailer_count].iov_len; - if (size > trailer_size) { - gossip_err("writev error: trailer size (%ld) != iov_len (%zd)\n", (unsigned long)trailer_size, size); - dev_req_release(buffer); - put_op(op); - return -EMSGSIZE; - } - /* Allocate a buffer large enough to hold the - * trailer bytes. - */ - op->downcall.trailer_buf = vmalloc(trailer_size); - if (op->downcall.trailer_buf != NULL) { - gossip_debug(GOSSIP_DEV_DEBUG, "vmalloc: %p\n", - op->downcall.trailer_buf); - ret = copy_from_user(op->downcall.trailer_buf, - iov[notrailer_count]. - iov_base, - size); - if (ret) { - gossip_err("Failed to copy trailer data from user space\n"); - dev_req_release(buffer); - gossip_debug(GOSSIP_DEV_DEBUG, - "vfree: %p\n", - op->downcall.trailer_buf); - vfree(op->downcall.trailer_buf); - op->downcall.trailer_buf = NULL; - put_op(op); - return -EIO; - } - memset(op->downcall.trailer_buf + size, 0, - trailer_size - size); - } else { - /* Change downcall status */ - op->downcall.status = -ENOMEM; - gossip_err("writev: could not vmalloc for trailer!\n"); - } - } - - /* if this operation is an I/O operation and if it was - * initiated on behalf of a *synchronous* VFS I/O operation, - * only then we need to wait - * for all data to be copied before we can return to avoid - * buffer corruption and races that can pull the buffers - * out from under us. - * - * Essentially we're synchronizing with other parts of the - * vfs implicitly by not allowing the user space - * application reading/writing this device to return until - * the buffers are done being used. - */ - if (op->upcall.type == ORANGEFS_VFS_OP_FILE_IO && - op->upcall.req.io.async_vfs_io == ORANGEFS_VFS_SYNC_IO) { - int timed_out = 0; - DECLARE_WAITQUEUE(wait_entry, current); - - /* tell the vfs op waiting on a waitqueue - * that this op is done - */ - spin_lock(&op->lock); - set_op_state_serviced(op); - spin_unlock(&op->lock); - - add_wait_queue_exclusive(&op->io_completion_waitq, - &wait_entry); - wake_up_interruptible(&op->waitq); - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock(&op->lock); - if (op->io_completed) { - spin_unlock(&op->lock); - break; - } - spin_unlock(&op->lock); - - if (!signal_pending(current)) { - int timeout = - MSECS_TO_JIFFIES(1000 * - op_timeout_secs); - if (!schedule_timeout(timeout)) { - gossip_debug(GOSSIP_DEV_DEBUG, "*** I/O wait time is up\n"); - timed_out = 1; - break; - } - continue; - } - - gossip_debug(GOSSIP_DEV_DEBUG, "*** signal on I/O wait -- aborting\n"); - break; - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&op->io_completion_waitq, - &wait_entry); - - /* NOTE: for I/O operations we handle releasing the op - * object except in the case of timeout. the reason we - * can't free the op in timeout cases is that the op - * service logic in the vfs retries operations using - * the same op ptr, thus it can't be freed. - */ - if (!timed_out) - op_release(op); - } else { - - /* - * tell the vfs op waiting on a waitqueue that - * this op is done - */ - spin_lock(&op->lock); - set_op_state_serviced(op); - spin_unlock(&op->lock); - /* - * for every other operation (i.e. non-I/O), we need to - * wake up the callers for downcall completion - * notification - */ - wake_up_interruptible(&op->waitq); - } - } else { - /* ignore downcalls that we're not interested in */ - gossip_debug(GOSSIP_DEV_DEBUG, - "WARNING: No one's waiting for tag %llu\n", - llu(tag)); - } - dev_req_release(buffer); - - return total_returned_size; -} - -static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, - struct iov_iter *iter) -{ - return orangefs_devreq_writev(iocb->ki_filp, - iter->iov, - iter->nr_segs, - &iocb->ki_pos); -} - -/* Returns whether any FS are still pending remounted */ -static int mark_all_pending_mounts(void) -{ - int unmounted = 1; - struct orangefs_sb_info_s *orangefs_sb = NULL; - - spin_lock(&orangefs_superblocks_lock); - list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) { - /* All of these file system require a remount */ - orangefs_sb->mount_pending = 1; - unmounted = 0; - } - spin_unlock(&orangefs_superblocks_lock); - return unmounted; -} - -/* - * Determine if a given file system needs to be remounted or not - * Returns -1 on error - * 0 if already mounted - * 1 if needs remount - */ -int fs_mount_pending(__s32 fsid) -{ - int mount_pending = -1; - struct orangefs_sb_info_s *orangefs_sb = NULL; - - spin_lock(&orangefs_superblocks_lock); - list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) { - if (orangefs_sb->fs_id == fsid) { - mount_pending = orangefs_sb->mount_pending; - break; - } - } - spin_unlock(&orangefs_superblocks_lock); - return mount_pending; -} - -/* - * NOTE: gets called when the last reference to this device is dropped. - * Using the open_access_count variable, we enforce a reference count - * on this file so that it can be opened by only one process at a time. - * the devreq_mutex is used to make sure all i/o has completed - * before we call orangefs_bufmap_finalize, and similar such tricky - * situations - */ -static int orangefs_devreq_release(struct inode *inode, struct file *file) -{ - int unmounted = 0; - - gossip_debug(GOSSIP_DEV_DEBUG, - "%s:pvfs2-client-core: exiting, closing device\n", - __func__); - - mutex_lock(&devreq_mutex); - orangefs_bufmap_finalize(); - - open_access_count--; - - unmounted = mark_all_pending_mounts(); - gossip_debug(GOSSIP_DEV_DEBUG, "ORANGEFS Device Close: Filesystem(s) %s\n", - (unmounted ? "UNMOUNTED" : "MOUNTED")); - mutex_unlock(&devreq_mutex); - - /* - * Walk through the list of ops in the request list, mark them - * as purged and wake them up. - */ - purge_waiting_ops(); - /* - * Walk through the hash table of in progress operations; mark - * them as purged and wake them up - */ - purge_inprogress_ops(); - gossip_debug(GOSSIP_DEV_DEBUG, - "pvfs2-client-core: device close complete\n"); - return 0; -} - -int is_daemon_in_service(void) -{ - int in_service; - - /* - * What this function does is checks if client-core is alive - * based on the access count we maintain on the device. - */ - mutex_lock(&devreq_mutex); - in_service = open_access_count == 1 ? 0 : -EIO; - mutex_unlock(&devreq_mutex); - return in_service; -} - -static inline long check_ioctl_command(unsigned int command) -{ - /* Check for valid ioctl codes */ - if (_IOC_TYPE(command) != ORANGEFS_DEV_MAGIC) { - gossip_err("device ioctl magic numbers don't match! Did you rebuild pvfs2-client-core/libpvfs2? [cmd %x, magic %x != %x]\n", - command, - _IOC_TYPE(command), - ORANGEFS_DEV_MAGIC); - return -EINVAL; - } - /* and valid ioctl commands */ - if (_IOC_NR(command) >= ORANGEFS_DEV_MAXNR || _IOC_NR(command) <= 0) { - gossip_err("Invalid ioctl command number [%d >= %d]\n", - _IOC_NR(command), ORANGEFS_DEV_MAXNR); - return -ENOIOCTLCMD; - } - return 0; -} - -static long dispatch_ioctl_command(unsigned int command, unsigned long arg) -{ - static __s32 magic = ORANGEFS_DEVREQ_MAGIC; - static __s32 max_up_size = MAX_ALIGNED_DEV_REQ_UPSIZE; - static __s32 max_down_size = MAX_ALIGNED_DEV_REQ_DOWNSIZE; - struct ORANGEFS_dev_map_desc user_desc; - int ret = 0; - struct dev_mask_info_s mask_info = { 0 }; - struct dev_mask2_info_s mask2_info = { 0, 0 }; - int upstream_kmod = 1; - struct list_head *tmp = NULL; - struct orangefs_sb_info_s *orangefs_sb = NULL; - - /* mtmoore: add locking here */ - - switch (command) { - case ORANGEFS_DEV_GET_MAGIC: - return ((put_user(magic, (__s32 __user *) arg) == -EFAULT) ? - -EIO : - 0); - case ORANGEFS_DEV_GET_MAX_UPSIZE: - return ((put_user(max_up_size, - (__s32 __user *) arg) == -EFAULT) ? - -EIO : - 0); - case ORANGEFS_DEV_GET_MAX_DOWNSIZE: - return ((put_user(max_down_size, - (__s32 __user *) arg) == -EFAULT) ? - -EIO : - 0); - case ORANGEFS_DEV_MAP: - ret = copy_from_user(&user_desc, - (struct ORANGEFS_dev_map_desc __user *) - arg, - sizeof(struct ORANGEFS_dev_map_desc)); - return ret ? -EIO : orangefs_bufmap_initialize(&user_desc); - case ORANGEFS_DEV_REMOUNT_ALL: - gossip_debug(GOSSIP_DEV_DEBUG, - "orangefs_devreq_ioctl: got ORANGEFS_DEV_REMOUNT_ALL\n"); - - /* - * remount all mounted orangefs volumes to regain the lost - * dynamic mount tables (if any) -- NOTE: this is done - * without keeping the superblock list locked due to the - * upcall/downcall waiting. also, the request semaphore is - * used to ensure that no operations will be serviced until - * all of the remounts are serviced (to avoid ops between - * mounts to fail) - */ - ret = mutex_lock_interruptible(&request_mutex); - if (ret < 0) - return ret; - gossip_debug(GOSSIP_DEV_DEBUG, - "orangefs_devreq_ioctl: priority remount in progress\n"); - list_for_each(tmp, &orangefs_superblocks) { - orangefs_sb = - list_entry(tmp, struct orangefs_sb_info_s, list); - if (orangefs_sb && (orangefs_sb->sb)) { - gossip_debug(GOSSIP_DEV_DEBUG, - "Remounting SB %p\n", - orangefs_sb); - - ret = orangefs_remount(orangefs_sb->sb); - if (ret) { - gossip_debug(GOSSIP_DEV_DEBUG, - "SB %p remount failed\n", - orangefs_sb); - break; - } - } - } - gossip_debug(GOSSIP_DEV_DEBUG, - "orangefs_devreq_ioctl: priority remount complete\n"); - mutex_unlock(&request_mutex); - return ret; - - case ORANGEFS_DEV_UPSTREAM: - ret = copy_to_user((void __user *)arg, - &upstream_kmod, - sizeof(upstream_kmod)); - - if (ret != 0) - return -EIO; - else - return ret; - - case ORANGEFS_DEV_CLIENT_MASK: - ret = copy_from_user(&mask2_info, - (void __user *)arg, - sizeof(struct dev_mask2_info_s)); - - if (ret != 0) - return -EIO; - - client_debug_mask.mask1 = mask2_info.mask1_value; - client_debug_mask.mask2 = mask2_info.mask2_value; - - pr_info("%s: client debug mask has been been received " - ":%llx: :%llx:\n", - __func__, - (unsigned long long)client_debug_mask.mask1, - (unsigned long long)client_debug_mask.mask2); - - return ret; - - case ORANGEFS_DEV_CLIENT_STRING: - ret = copy_from_user(&client_debug_array_string, - (void __user *)arg, - ORANGEFS_MAX_DEBUG_STRING_LEN); - if (ret != 0) { - pr_info("%s: " - "ORANGEFS_DEV_CLIENT_STRING: copy_from_user failed" - "\n", - __func__); - return -EIO; - } - - pr_info("%s: client debug array string has been been received." - "\n", - __func__); - - if (!help_string_initialized) { - - /* Free the "we don't know yet" default string... */ - kfree(debug_help_string); - - /* build a proper debug help string */ - if (orangefs_prepare_debugfs_help_string(0)) { - gossip_err("%s: " - "prepare_debugfs_help_string failed" - "\n", - __func__); - return -EIO; - } - - /* Replace the boilerplate boot-time debug-help file. */ - debugfs_remove(help_file_dentry); - - help_file_dentry = - debugfs_create_file( - ORANGEFS_KMOD_DEBUG_HELP_FILE, - 0444, - debug_dir, - debug_help_string, - &debug_help_fops); - - if (!help_file_dentry) { - gossip_err("%s: debugfs_create_file failed for" - " :%s:!\n", - __func__, - ORANGEFS_KMOD_DEBUG_HELP_FILE); - return -EIO; - } - } - - debug_mask_to_string(&client_debug_mask, 1); - - debugfs_remove(client_debug_dentry); - - orangefs_client_debug_init(); - - help_string_initialized++; - - return ret; - - case ORANGEFS_DEV_DEBUG: - ret = copy_from_user(&mask_info, - (void __user *)arg, - sizeof(mask_info)); - - if (ret != 0) - return -EIO; - - if (mask_info.mask_type == KERNEL_MASK) { - if ((mask_info.mask_value == 0) - && (kernel_mask_set_mod_init)) { - /* - * the kernel debug mask was set when the - * kernel module was loaded; don't override - * it if the client-core was started without - * a value for ORANGEFS_KMODMASK. - */ - return 0; - } - debug_mask_to_string(&mask_info.mask_value, - mask_info.mask_type); - gossip_debug_mask = mask_info.mask_value; - pr_info("ORANGEFS: kernel debug mask has been modified to " - ":%s: :%llx:\n", - kernel_debug_string, - (unsigned long long)gossip_debug_mask); - } else if (mask_info.mask_type == CLIENT_MASK) { - debug_mask_to_string(&mask_info.mask_value, - mask_info.mask_type); - pr_info("ORANGEFS: client debug mask has been modified to" - ":%s: :%llx:\n", - client_debug_string, - llu(mask_info.mask_value)); - } else { - gossip_lerr("Invalid mask type....\n"); - return -EINVAL; - } - - return ret; - - default: - return -ENOIOCTLCMD; - } - return -ENOIOCTLCMD; -} - -static long orangefs_devreq_ioctl(struct file *file, - unsigned int command, unsigned long arg) -{ - long ret; - - /* Check for properly constructed commands */ - ret = check_ioctl_command(command); - if (ret < 0) - return (int)ret; - - return (int)dispatch_ioctl_command(command, arg); -} - -#ifdef CONFIG_COMPAT /* CONFIG_COMPAT is in .config */ - -/* Compat structure for the ORANGEFS_DEV_MAP ioctl */ -struct ORANGEFS_dev_map_desc32 { - compat_uptr_t ptr; - __s32 total_size; - __s32 size; - __s32 count; -}; - -static unsigned long translate_dev_map26(unsigned long args, long *error) -{ - struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args; - /* - * Depending on the architecture, allocate some space on the - * user-call-stack based on our expected layout. - */ - struct ORANGEFS_dev_map_desc __user *p = - compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - - *error = 0; - /* get the ptr from the 32 bit user-space */ - if (get_user(addr, &p32->ptr)) - goto err; - /* try to put that into a 64-bit layout */ - if (put_user(compat_ptr(addr), &p->ptr)) - goto err; - /* copy the remaining fields */ - if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32))) - goto err; - if (copy_in_user(&p->size, &p32->size, sizeof(__s32))) - goto err; - if (copy_in_user(&p->count, &p32->count, sizeof(__s32))) - goto err; - return (unsigned long)p; -err: - *error = -EFAULT; - return 0; -} - -/* - * 32 bit user-space apps' ioctl handlers when kernel modules - * is compiled as a 64 bit one - */ -static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long args) -{ - long ret; - unsigned long arg = args; - - /* Check for properly constructed commands */ - ret = check_ioctl_command(cmd); - if (ret < 0) - return ret; - if (cmd == ORANGEFS_DEV_MAP) { - /* - * convert the arguments to what we expect internally - * in kernel space - */ - arg = translate_dev_map26(args, &ret); - if (ret < 0) { - gossip_err("Could not translate dev map\n"); - return ret; - } - } - /* no other ioctl requires translation */ - return dispatch_ioctl_command(cmd, arg); -} - -#endif /* CONFIG_COMPAT is in .config */ - -/* - * The following two ioctl32 functions had been refactored into the above - * CONFIG_COMPAT ifdef, but that was an over simplification that was - * not noticed until we tried to compile on power pc... - */ -#if (defined(CONFIG_COMPAT) && !defined(HAVE_REGISTER_IOCTL32_CONVERSION)) || !defined(CONFIG_COMPAT) -static int orangefs_ioctl32_init(void) -{ - return 0; -} - -static void orangefs_ioctl32_cleanup(void) -{ - return; -} -#endif - -/* the assigned character device major number */ -static int orangefs_dev_major; - -/* - * Initialize orangefs device specific state: - * Must be called at module load time only - */ -int orangefs_dev_init(void) -{ - int ret; - - /* register the ioctl32 sub-system */ - ret = orangefs_ioctl32_init(); - if (ret < 0) - return ret; - - /* register orangefs-req device */ - orangefs_dev_major = register_chrdev(0, - ORANGEFS_REQDEVICE_NAME, - &orangefs_devreq_file_operations); - if (orangefs_dev_major < 0) { - gossip_debug(GOSSIP_DEV_DEBUG, - "Failed to register /dev/%s (error %d)\n", - ORANGEFS_REQDEVICE_NAME, orangefs_dev_major); - orangefs_ioctl32_cleanup(); - return orangefs_dev_major; - } - - gossip_debug(GOSSIP_DEV_DEBUG, - "*** /dev/%s character device registered ***\n", - ORANGEFS_REQDEVICE_NAME); - gossip_debug(GOSSIP_DEV_DEBUG, "'mknod /dev/%s c %d 0'.\n", - ORANGEFS_REQDEVICE_NAME, orangefs_dev_major); - return 0; -} - -void orangefs_dev_cleanup(void) -{ - unregister_chrdev(orangefs_dev_major, ORANGEFS_REQDEVICE_NAME); - gossip_debug(GOSSIP_DEV_DEBUG, - "*** /dev/%s character device unregistered ***\n", - ORANGEFS_REQDEVICE_NAME); - /* unregister the ioctl32 sub-system */ - orangefs_ioctl32_cleanup(); -} - -static unsigned int orangefs_devreq_poll(struct file *file, - struct poll_table_struct *poll_table) -{ - int poll_revent_mask = 0; - - if (open_access_count == 1) { - poll_wait(file, &orangefs_request_list_waitq, poll_table); - - spin_lock(&orangefs_request_list_lock); - if (!list_empty(&orangefs_request_list)) - poll_revent_mask |= POLL_IN; - spin_unlock(&orangefs_request_list_lock); - } - return poll_revent_mask; -} - -const struct file_operations orangefs_devreq_file_operations = { - .owner = THIS_MODULE, - .read = orangefs_devreq_read, - .write_iter = orangefs_devreq_write_iter, - .open = orangefs_devreq_open, - .release = orangefs_devreq_release, - .unlocked_ioctl = orangefs_devreq_ioctl, - -#ifdef CONFIG_COMPAT /* CONFIG_COMPAT is in .config */ - .compat_ioctl = orangefs_devreq_compat_ioctl, -#endif - .poll = orangefs_devreq_poll -}; diff --git a/fs/orangefs/dir.c b/fs/orangefs/dir.c index 452d589b9747..c043894fc2bd 100644 --- a/fs/orangefs/dir.c +++ b/fs/orangefs/dir.c @@ -5,8 +5,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" struct readdir_handle_s { int buffer_index; diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index ae5d8ed67ed5..171013ae0036 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -9,8 +9,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" #include #include @@ -186,7 +186,7 @@ populate_shared_memory: } if (ret < 0) { - handle_io_error(); /* defined in pvfs2-kernel.h */ + handle_io_error(); /* * don't write an error to syslog on signaled operation * termination unless we've got debugging turned on, as diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c index 58e83182d3dc..4724c92b61ac 100644 --- a/fs/orangefs/inode.c +++ b/fs/orangefs/inode.c @@ -9,8 +9,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" static int read_one_page(struct page *page) { @@ -125,7 +125,7 @@ static int orangefs_releasepage(struct page *page, gfp_t foo) * AIO. Modeled after NFS, they do this too. */ /* - * static ssize_t pvfs2_direct_IO(int rw, + * static ssize_t orangefs_direct_IO(int rw, * struct kiocb *iocb, * struct iov_iter *iter, * loff_t offset) @@ -150,7 +150,7 @@ const struct address_space_operations orangefs_address_operations = { .readpages = orangefs_readpages, .invalidatepage = orangefs_invalidatepage, .releasepage = orangefs_releasepage, -/* .direct_IO = pvfs2_direct_IO */ +/* .direct_IO = orangefs_direct_IO */ }; static int orangefs_setattr_size(struct inode *inode, struct iattr *iattr) diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 333c87c8b0f5..63aa1e7fbdb6 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -9,7 +9,7 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" +#include "orangefs-kernel.h" /* * Get a newly allocated inode to go with a negative dentry. diff --git a/fs/orangefs/orangefs-bufmap.c b/fs/orangefs/orangefs-bufmap.c new file mode 100644 index 000000000000..c5368d852ee2 --- /dev/null +++ b/fs/orangefs/orangefs-bufmap.c @@ -0,0 +1,558 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ +#include "protocol.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" + +DECLARE_WAIT_QUEUE_HEAD(orangefs_bufmap_init_waitq); + +static struct orangefs_bufmap { + atomic_t refcnt; + + int desc_size; + int desc_shift; + int desc_count; + int total_size; + int page_count; + + struct page **page_array; + struct orangefs_bufmap_desc *desc_array; + + /* array to track usage of buffer descriptors */ + int *buffer_index_array; + spinlock_t buffer_index_lock; + + /* array to track usage of buffer descriptors for readdir */ + int readdir_index_array[ORANGEFS_READDIR_DEFAULT_DESC_COUNT]; + spinlock_t readdir_index_lock; +} *__orangefs_bufmap; + +static DEFINE_SPINLOCK(orangefs_bufmap_lock); + +static void +orangefs_bufmap_unmap(struct orangefs_bufmap *bufmap) +{ + int i; + + for (i = 0; i < bufmap->page_count; i++) + page_cache_release(bufmap->page_array[i]); +} + +static void +orangefs_bufmap_free(struct orangefs_bufmap *bufmap) +{ + kfree(bufmap->page_array); + kfree(bufmap->desc_array); + kfree(bufmap->buffer_index_array); + kfree(bufmap); +} + +struct orangefs_bufmap *orangefs_bufmap_ref(void) +{ + struct orangefs_bufmap *bufmap = NULL; + + spin_lock(&orangefs_bufmap_lock); + if (__orangefs_bufmap) { + bufmap = __orangefs_bufmap; + atomic_inc(&bufmap->refcnt); + } + spin_unlock(&orangefs_bufmap_lock); + return bufmap; +} + +void orangefs_bufmap_unref(struct orangefs_bufmap *bufmap) +{ + if (atomic_dec_and_lock(&bufmap->refcnt, &orangefs_bufmap_lock)) { + __orangefs_bufmap = NULL; + spin_unlock(&orangefs_bufmap_lock); + + orangefs_bufmap_unmap(bufmap); + orangefs_bufmap_free(bufmap); + } +} + +inline int orangefs_bufmap_size_query(void) +{ + struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); + int size = bufmap ? bufmap->desc_size : 0; + + orangefs_bufmap_unref(bufmap); + return size; +} + +inline int orangefs_bufmap_shift_query(void) +{ + struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); + int shift = bufmap ? bufmap->desc_shift : 0; + + orangefs_bufmap_unref(bufmap); + return shift; +} + +static DECLARE_WAIT_QUEUE_HEAD(bufmap_waitq); +static DECLARE_WAIT_QUEUE_HEAD(readdir_waitq); + +/* + * get_bufmap_init + * + * If bufmap_init is 1, then the shared memory system, including the + * buffer_index_array, is available. Otherwise, it is not. + * + * returns the value of bufmap_init + */ +int get_bufmap_init(void) +{ + return __orangefs_bufmap ? 1 : 0; +} + + +static struct orangefs_bufmap * +orangefs_bufmap_alloc(struct ORANGEFS_dev_map_desc *user_desc) +{ + struct orangefs_bufmap *bufmap; + + bufmap = kzalloc(sizeof(*bufmap), GFP_KERNEL); + if (!bufmap) + goto out; + + atomic_set(&bufmap->refcnt, 1); + bufmap->total_size = user_desc->total_size; + bufmap->desc_count = user_desc->count; + bufmap->desc_size = user_desc->size; + bufmap->desc_shift = ilog2(bufmap->desc_size); + + spin_lock_init(&bufmap->buffer_index_lock); + bufmap->buffer_index_array = + kcalloc(bufmap->desc_count, sizeof(int), GFP_KERNEL); + if (!bufmap->buffer_index_array) { + gossip_err("orangefs: could not allocate %d buffer indices\n", + bufmap->desc_count); + goto out_free_bufmap; + } + spin_lock_init(&bufmap->readdir_index_lock); + + bufmap->desc_array = + kcalloc(bufmap->desc_count, sizeof(struct orangefs_bufmap_desc), + GFP_KERNEL); + if (!bufmap->desc_array) { + gossip_err("orangefs: could not allocate %d descriptors\n", + bufmap->desc_count); + goto out_free_index_array; + } + + bufmap->page_count = bufmap->total_size / PAGE_SIZE; + + /* allocate storage to track our page mappings */ + bufmap->page_array = + kcalloc(bufmap->page_count, sizeof(struct page *), GFP_KERNEL); + if (!bufmap->page_array) + goto out_free_desc_array; + + return bufmap; + +out_free_desc_array: + kfree(bufmap->desc_array); +out_free_index_array: + kfree(bufmap->buffer_index_array); +out_free_bufmap: + kfree(bufmap); +out: + return NULL; +} + +static int +orangefs_bufmap_map(struct orangefs_bufmap *bufmap, + struct ORANGEFS_dev_map_desc *user_desc) +{ + int pages_per_desc = bufmap->desc_size / PAGE_SIZE; + int offset = 0, ret, i; + + /* map the pages */ + ret = get_user_pages_fast((unsigned long)user_desc->ptr, + bufmap->page_count, 1, bufmap->page_array); + + if (ret < 0) + return ret; + + if (ret != bufmap->page_count) { + gossip_err("orangefs error: asked for %d pages, only got %d.\n", + bufmap->page_count, ret); + + for (i = 0; i < ret; i++) { + SetPageError(bufmap->page_array[i]); + page_cache_release(bufmap->page_array[i]); + } + return -ENOMEM; + } + + /* + * ideally we want to get kernel space pointers for each page, but + * we can't kmap that many pages at once if highmem is being used. + * so instead, we just kmap/kunmap the page address each time the + * kaddr is needed. + */ + for (i = 0; i < bufmap->page_count; i++) + flush_dcache_page(bufmap->page_array[i]); + + /* build a list of available descriptors */ + for (offset = 0, i = 0; i < bufmap->desc_count; i++) { + bufmap->desc_array[i].page_array = &bufmap->page_array[offset]; + bufmap->desc_array[i].array_count = pages_per_desc; + bufmap->desc_array[i].uaddr = + (user_desc->ptr + (i * pages_per_desc * PAGE_SIZE)); + offset += pages_per_desc; + } + + return 0; +} + +/* + * orangefs_bufmap_initialize() + * + * initializes the mapped buffer interface + * + * returns 0 on success, -errno on failure + */ +int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc) +{ + struct orangefs_bufmap *bufmap; + int ret = -EINVAL; + + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "orangefs_bufmap_initialize: called (ptr (" + "%p) sz (%d) cnt(%d).\n", + user_desc->ptr, + user_desc->size, + user_desc->count); + + /* + * sanity check alignment and size of buffer that caller wants to + * work with + */ + if (PAGE_ALIGN((unsigned long)user_desc->ptr) != + (unsigned long)user_desc->ptr) { + gossip_err("orangefs error: memory alignment (front). %p\n", + user_desc->ptr); + goto out; + } + + if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->total_size)) + != (unsigned long)(user_desc->ptr + user_desc->total_size)) { + gossip_err("orangefs error: memory alignment (back).(%p + %d)\n", + user_desc->ptr, + user_desc->total_size); + goto out; + } + + if (user_desc->total_size != (user_desc->size * user_desc->count)) { + gossip_err("orangefs error: user provided an oddly sized buffer: (%d, %d, %d)\n", + user_desc->total_size, + user_desc->size, + user_desc->count); + goto out; + } + + if ((user_desc->size % PAGE_SIZE) != 0) { + gossip_err("orangefs error: bufmap size not page size divisible (%d).\n", + user_desc->size); + goto out; + } + + ret = -ENOMEM; + bufmap = orangefs_bufmap_alloc(user_desc); + if (!bufmap) + goto out; + + ret = orangefs_bufmap_map(bufmap, user_desc); + if (ret) + goto out_free_bufmap; + + + spin_lock(&orangefs_bufmap_lock); + if (__orangefs_bufmap) { + spin_unlock(&orangefs_bufmap_lock); + gossip_err("orangefs: error: bufmap already initialized.\n"); + ret = -EALREADY; + goto out_unmap_bufmap; + } + __orangefs_bufmap = bufmap; + spin_unlock(&orangefs_bufmap_lock); + + /* + * If there are operations in orangefs_bufmap_init_waitq, wake them up. + * This scenario occurs when the client-core is restarted and I/O + * requests in the in-progress or waiting tables are restarted. I/O + * requests cannot be restarted until the shared memory system is + * completely re-initialized, so we put the I/O requests in this + * waitq until initialization has completed. NOTE: the I/O requests + * are also on a timer, so they don't wait forever just in case the + * client-core doesn't come back up. + */ + wake_up_interruptible(&orangefs_bufmap_init_waitq); + + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "orangefs_bufmap_initialize: exiting normally\n"); + return 0; + +out_unmap_bufmap: + orangefs_bufmap_unmap(bufmap); +out_free_bufmap: + orangefs_bufmap_free(bufmap); +out: + return ret; +} + +/* + * orangefs_bufmap_finalize() + * + * shuts down the mapped buffer interface and releases any resources + * associated with it + * + * no return value + */ +void orangefs_bufmap_finalize(void) +{ + gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs_bufmap_finalize: called\n"); + BUG_ON(!__orangefs_bufmap); + orangefs_bufmap_unref(__orangefs_bufmap); + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "orangefs_bufmap_finalize: exiting normally\n"); +} + +struct slot_args { + int slot_count; + int *slot_array; + spinlock_t *slot_lock; + wait_queue_head_t *slot_wq; +}; + +static int wait_for_a_slot(struct slot_args *slargs, int *buffer_index) +{ + int ret = -1; + int i = 0; + DECLARE_WAITQUEUE(my_wait, current); + + + add_wait_queue_exclusive(slargs->slot_wq, &my_wait); + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + + /* + * check for available desc, slot_lock is the appropriate + * index_lock + */ + spin_lock(slargs->slot_lock); + for (i = 0; i < slargs->slot_count; i++) + if (slargs->slot_array[i] == 0) { + slargs->slot_array[i] = 1; + *buffer_index = i; + ret = 0; + break; + } + spin_unlock(slargs->slot_lock); + + /* if we acquired a buffer, then break out of while */ + if (ret == 0) + break; + + if (!signal_pending(current)) { + int timeout = + MSECS_TO_JIFFIES(1000 * slot_timeout_secs); + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "[BUFMAP]: waiting %d " + "seconds for a slot\n", + slot_timeout_secs); + if (!schedule_timeout(timeout)) { + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "*** wait_for_a_slot timed out\n"); + ret = -ETIMEDOUT; + break; + } + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "[BUFMAP]: woken up by a slot becoming available.\n"); + continue; + } + + gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs: %s interrupted.\n", + __func__); + ret = -EINTR; + break; + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(slargs->slot_wq, &my_wait); + return ret; +} + +static void put_back_slot(struct slot_args *slargs, int buffer_index) +{ + /* slot_lock is the appropriate index_lock */ + spin_lock(slargs->slot_lock); + if (buffer_index < 0 || buffer_index >= slargs->slot_count) { + spin_unlock(slargs->slot_lock); + return; + } + + /* put the desc back on the queue */ + slargs->slot_array[buffer_index] = 0; + spin_unlock(slargs->slot_lock); + + /* wake up anyone who may be sleeping on the queue */ + wake_up_interruptible(slargs->slot_wq); +} + +/* + * orangefs_bufmap_get() + * + * gets a free mapped buffer descriptor, will sleep until one becomes + * available if necessary + * + * returns 0 on success, -errno on failure + */ +int orangefs_bufmap_get(struct orangefs_bufmap **mapp, int *buffer_index) +{ + struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); + struct slot_args slargs; + int ret; + + if (!bufmap) { + gossip_err("orangefs: please confirm that pvfs2-client daemon is running.\n"); + return -EIO; + } + + slargs.slot_count = bufmap->desc_count; + slargs.slot_array = bufmap->buffer_index_array; + slargs.slot_lock = &bufmap->buffer_index_lock; + slargs.slot_wq = &bufmap_waitq; + ret = wait_for_a_slot(&slargs, buffer_index); + if (ret) + orangefs_bufmap_unref(bufmap); + *mapp = bufmap; + return ret; +} + +/* + * orangefs_bufmap_put() + * + * returns a mapped buffer descriptor to the collection + * + * no return value + */ +void orangefs_bufmap_put(struct orangefs_bufmap *bufmap, int buffer_index) +{ + struct slot_args slargs; + + slargs.slot_count = bufmap->desc_count; + slargs.slot_array = bufmap->buffer_index_array; + slargs.slot_lock = &bufmap->buffer_index_lock; + slargs.slot_wq = &bufmap_waitq; + put_back_slot(&slargs, buffer_index); + orangefs_bufmap_unref(bufmap); +} + +/* + * readdir_index_get() + * + * gets a free descriptor, will sleep until one becomes + * available if necessary. + * Although the readdir buffers are not mapped into kernel space + * we could do that at a later point of time. Regardless, these + * indices are used by the client-core. + * + * returns 0 on success, -errno on failure + */ +int readdir_index_get(struct orangefs_bufmap **mapp, int *buffer_index) +{ + struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); + struct slot_args slargs; + int ret; + + if (!bufmap) { + gossip_err("orangefs: please confirm that pvfs2-client daemon is running.\n"); + return -EIO; + } + + slargs.slot_count = ORANGEFS_READDIR_DEFAULT_DESC_COUNT; + slargs.slot_array = bufmap->readdir_index_array; + slargs.slot_lock = &bufmap->readdir_index_lock; + slargs.slot_wq = &readdir_waitq; + ret = wait_for_a_slot(&slargs, buffer_index); + if (ret) + orangefs_bufmap_unref(bufmap); + *mapp = bufmap; + return ret; +} + +void readdir_index_put(struct orangefs_bufmap *bufmap, int buffer_index) +{ + struct slot_args slargs; + + slargs.slot_count = ORANGEFS_READDIR_DEFAULT_DESC_COUNT; + slargs.slot_array = bufmap->readdir_index_array; + slargs.slot_lock = &bufmap->readdir_index_lock; + slargs.slot_wq = &readdir_waitq; + put_back_slot(&slargs, buffer_index); + orangefs_bufmap_unref(bufmap); +} + +int orangefs_bufmap_copy_from_iovec(struct orangefs_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index, + size_t size) +{ + struct orangefs_bufmap_desc *to = &bufmap->desc_array[buffer_index]; + int i; + + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "%s: buffer_index:%d: size:%zu:\n", + __func__, buffer_index, size); + + + for (i = 0; size; i++) { + struct page *page = to->page_array[i]; + size_t n = size; + if (n > PAGE_SIZE) + n = PAGE_SIZE; + n = copy_page_from_iter(page, 0, n, iter); + if (!n) + return -EFAULT; + size -= n; + } + return 0; + +} + +/* + * Iterate through the array of pages containing the bytes from + * a file being read. + * + */ +int orangefs_bufmap_copy_to_iovec(struct orangefs_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index, + size_t size) +{ + struct orangefs_bufmap_desc *from = &bufmap->desc_array[buffer_index]; + int i; + + gossip_debug(GOSSIP_BUFMAP_DEBUG, + "%s: buffer_index:%d: size:%zu:\n", + __func__, buffer_index, size); + + + for (i = 0; size; i++) { + struct page *page = from->page_array[i]; + size_t n = size; + if (n > PAGE_SIZE) + n = PAGE_SIZE; + n = copy_page_to_iter(page, 0, n, iter); + if (!n) + return -EFAULT; + size -= n; + } + return 0; +} diff --git a/fs/orangefs/orangefs-bufmap.h b/fs/orangefs/orangefs-bufmap.h new file mode 100644 index 000000000000..91d1755c231a --- /dev/null +++ b/fs/orangefs/orangefs-bufmap.h @@ -0,0 +1,62 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +#ifndef __ORANGEFS_BUFMAP_H +#define __ORANGEFS_BUFMAP_H + +/* used to describe mapped buffers */ +struct orangefs_bufmap_desc { + void *uaddr; /* user space address pointer */ + struct page **page_array; /* array of mapped pages */ + int array_count; /* size of above arrays */ + struct list_head list_link; +}; + +struct orangefs_bufmap; + +struct orangefs_bufmap *orangefs_bufmap_ref(void); +void orangefs_bufmap_unref(struct orangefs_bufmap *bufmap); + +/* + * orangefs_bufmap_size_query is now an inline function because buffer + * sizes are not hardcoded + */ +int orangefs_bufmap_size_query(void); + +int orangefs_bufmap_shift_query(void); + +int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc); + +int get_bufmap_init(void); + +void orangefs_bufmap_finalize(void); + +int orangefs_bufmap_get(struct orangefs_bufmap **mapp, int *buffer_index); + +void orangefs_bufmap_put(struct orangefs_bufmap *bufmap, int buffer_index); + +int readdir_index_get(struct orangefs_bufmap **mapp, int *buffer_index); + +void readdir_index_put(struct orangefs_bufmap *bufmap, int buffer_index); + +int orangefs_bufmap_copy_from_iovec(struct orangefs_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index, + size_t size); + +int orangefs_bufmap_copy_to_iovec(struct orangefs_bufmap *bufmap, + struct iov_iter *iter, + int buffer_index, + size_t size); + +size_t orangefs_bufmap_copy_to_user_task_iovec(struct task_struct *tsk, + struct iovec *iovec, + unsigned long nr_segs, + struct orangefs_bufmap *bufmap, + int buffer_index, + size_t bytes_to_be_copied); + +#endif /* __ORANGEFS_BUFMAP_H */ diff --git a/fs/orangefs/orangefs-cache.c b/fs/orangefs/orangefs-cache.c new file mode 100644 index 000000000000..57e270246e3d --- /dev/null +++ b/fs/orangefs/orangefs-cache.c @@ -0,0 +1,246 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +#include "protocol.h" +#include "orangefs-kernel.h" + +/* tags assigned to kernel upcall operations */ +static __u64 next_tag_value; +static DEFINE_SPINLOCK(next_tag_value_lock); + +/* the orangefs memory caches */ + +/* a cache for orangefs upcall/downcall operations */ +static struct kmem_cache *op_cache; + +/* a cache for device (/dev/pvfs2-req) communication */ +static struct kmem_cache *dev_req_cache; + +/* a cache for orangefs_kiocb objects (i.e orangefs iocb structures ) */ +static struct kmem_cache *orangefs_kiocb_cache; + +int op_cache_initialize(void) +{ + op_cache = kmem_cache_create("orangefs_op_cache", + sizeof(struct orangefs_kernel_op_s), + 0, + ORANGEFS_CACHE_CREATE_FLAGS, + NULL); + + if (!op_cache) { + gossip_err("Cannot create orangefs_op_cache\n"); + return -ENOMEM; + } + + /* initialize our atomic tag counter */ + spin_lock(&next_tag_value_lock); + next_tag_value = 100; + spin_unlock(&next_tag_value_lock); + return 0; +} + +int op_cache_finalize(void) +{ + kmem_cache_destroy(op_cache); + return 0; +} + +char *get_opname_string(struct orangefs_kernel_op_s *new_op) +{ + if (new_op) { + __s32 type = new_op->upcall.type; + + if (type == ORANGEFS_VFS_OP_FILE_IO) + return "OP_FILE_IO"; + else if (type == ORANGEFS_VFS_OP_LOOKUP) + return "OP_LOOKUP"; + else if (type == ORANGEFS_VFS_OP_CREATE) + return "OP_CREATE"; + else if (type == ORANGEFS_VFS_OP_GETATTR) + return "OP_GETATTR"; + else if (type == ORANGEFS_VFS_OP_REMOVE) + return "OP_REMOVE"; + else if (type == ORANGEFS_VFS_OP_MKDIR) + return "OP_MKDIR"; + else if (type == ORANGEFS_VFS_OP_READDIR) + return "OP_READDIR"; + else if (type == ORANGEFS_VFS_OP_READDIRPLUS) + return "OP_READDIRPLUS"; + else if (type == ORANGEFS_VFS_OP_SETATTR) + return "OP_SETATTR"; + else if (type == ORANGEFS_VFS_OP_SYMLINK) + return "OP_SYMLINK"; + else if (type == ORANGEFS_VFS_OP_RENAME) + return "OP_RENAME"; + else if (type == ORANGEFS_VFS_OP_STATFS) + return "OP_STATFS"; + else if (type == ORANGEFS_VFS_OP_TRUNCATE) + return "OP_TRUNCATE"; + else if (type == ORANGEFS_VFS_OP_MMAP_RA_FLUSH) + return "OP_MMAP_RA_FLUSH"; + else if (type == ORANGEFS_VFS_OP_FS_MOUNT) + return "OP_FS_MOUNT"; + else if (type == ORANGEFS_VFS_OP_FS_UMOUNT) + return "OP_FS_UMOUNT"; + else if (type == ORANGEFS_VFS_OP_GETXATTR) + return "OP_GETXATTR"; + else if (type == ORANGEFS_VFS_OP_SETXATTR) + return "OP_SETXATTR"; + else if (type == ORANGEFS_VFS_OP_LISTXATTR) + return "OP_LISTXATTR"; + else if (type == ORANGEFS_VFS_OP_REMOVEXATTR) + return "OP_REMOVEXATTR"; + else if (type == ORANGEFS_VFS_OP_PARAM) + return "OP_PARAM"; + else if (type == ORANGEFS_VFS_OP_PERF_COUNT) + return "OP_PERF_COUNT"; + else if (type == ORANGEFS_VFS_OP_CANCEL) + return "OP_CANCEL"; + else if (type == ORANGEFS_VFS_OP_FSYNC) + return "OP_FSYNC"; + else if (type == ORANGEFS_VFS_OP_FSKEY) + return "OP_FSKEY"; + } + return "OP_UNKNOWN?"; +} + +struct orangefs_kernel_op_s *op_alloc(__s32 type) +{ + struct orangefs_kernel_op_s *new_op = NULL; + + new_op = kmem_cache_alloc(op_cache, ORANGEFS_CACHE_ALLOC_FLAGS); + if (new_op) { + memset(new_op, 0, sizeof(struct orangefs_kernel_op_s)); + + INIT_LIST_HEAD(&new_op->list); + spin_lock_init(&new_op->lock); + init_waitqueue_head(&new_op->waitq); + + init_waitqueue_head(&new_op->io_completion_waitq); + atomic_set(&new_op->aio_ref_count, 0); + + orangefs_op_initialize(new_op); + + /* initialize the op specific tag and upcall credentials */ + spin_lock(&next_tag_value_lock); + new_op->tag = next_tag_value++; + if (next_tag_value == 0) + next_tag_value = 100; + spin_unlock(&next_tag_value_lock); + new_op->upcall.type = type; + new_op->attempts = 0; + gossip_debug(GOSSIP_CACHE_DEBUG, + "Alloced OP (%p: %llu %s)\n", + new_op, + llu(new_op->tag), + get_opname_string(new_op)); + + new_op->upcall.uid = from_kuid(current_user_ns(), + current_fsuid()); + + new_op->upcall.gid = from_kgid(current_user_ns(), + current_fsgid()); + } else { + gossip_err("op_alloc: kmem_cache_alloc failed!\n"); + } + return new_op; +} + +void op_release(struct orangefs_kernel_op_s *orangefs_op) +{ + if (orangefs_op) { + gossip_debug(GOSSIP_CACHE_DEBUG, + "Releasing OP (%p: %llu)\n", + orangefs_op, + llu(orangefs_op->tag)); + orangefs_op_initialize(orangefs_op); + kmem_cache_free(op_cache, orangefs_op); + } else { + gossip_err("NULL pointer in op_release\n"); + } +} + +int dev_req_cache_initialize(void) +{ + dev_req_cache = kmem_cache_create("orangefs_devreqcache", + MAX_ALIGNED_DEV_REQ_DOWNSIZE, + 0, + ORANGEFS_CACHE_CREATE_FLAGS, + NULL); + + if (!dev_req_cache) { + gossip_err("Cannot create orangefs_dev_req_cache\n"); + return -ENOMEM; + } + return 0; +} + +int dev_req_cache_finalize(void) +{ + kmem_cache_destroy(dev_req_cache); + return 0; +} + +void *dev_req_alloc(void) +{ + void *buffer; + + buffer = kmem_cache_alloc(dev_req_cache, ORANGEFS_CACHE_ALLOC_FLAGS); + if (buffer == NULL) + gossip_err("Failed to allocate from dev_req_cache\n"); + else + memset(buffer, 0, sizeof(MAX_ALIGNED_DEV_REQ_DOWNSIZE)); + return buffer; +} + +void dev_req_release(void *buffer) +{ + if (buffer) + kmem_cache_free(dev_req_cache, buffer); + else + gossip_err("NULL pointer passed to dev_req_release\n"); +} + +int kiocb_cache_initialize(void) +{ + orangefs_kiocb_cache = kmem_cache_create("orangefs_kiocbcache", + sizeof(struct orangefs_kiocb_s), + 0, + ORANGEFS_CACHE_CREATE_FLAGS, + NULL); + + if (!orangefs_kiocb_cache) { + gossip_err("Cannot create orangefs_kiocb_cache!\n"); + return -ENOMEM; + } + return 0; +} + +int kiocb_cache_finalize(void) +{ + kmem_cache_destroy(orangefs_kiocb_cache); + return 0; +} + +struct orangefs_kiocb_s *kiocb_alloc(void) +{ + struct orangefs_kiocb_s *x = NULL; + + x = kmem_cache_alloc(orangefs_kiocb_cache, ORANGEFS_CACHE_ALLOC_FLAGS); + if (x == NULL) + gossip_err("kiocb_alloc: kmem_cache_alloc failed!\n"); + else + memset(x, 0, sizeof(struct orangefs_kiocb_s)); + return x; +} + +void kiocb_release(struct orangefs_kiocb_s *x) +{ + if (x) + kmem_cache_free(orangefs_kiocb_cache, x); + else + gossip_err("kiocb_release: kmem_cache_free NULL pointer!\n"); +} diff --git a/fs/orangefs/orangefs-debug.h b/fs/orangefs/orangefs-debug.h new file mode 100644 index 000000000000..e6b4baa5e8fb --- /dev/null +++ b/fs/orangefs/orangefs-debug.h @@ -0,0 +1,292 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +/* This file just defines debugging masks to be used with the gossip + * logging utility. All debugging masks for ORANGEFS are kept here to make + * sure we don't have collisions. + */ + +#ifndef __ORANGEFS_DEBUG_H +#define __ORANGEFS_DEBUG_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#define GOSSIP_NO_DEBUG (__u64)0 +#define GOSSIP_BMI_DEBUG_TCP ((__u64)1 << 0) +#define GOSSIP_BMI_DEBUG_CONTROL ((__u64)1 << 1) +#define GOSSIP_BMI_DEBUG_OFFSETS ((__u64)1 << 2) +#define GOSSIP_BMI_DEBUG_GM ((__u64)1 << 3) +#define GOSSIP_JOB_DEBUG ((__u64)1 << 4) +#define GOSSIP_SERVER_DEBUG ((__u64)1 << 5) +#define GOSSIP_STO_DEBUG_CTRL ((__u64)1 << 6) +#define GOSSIP_STO_DEBUG_DEFAULT ((__u64)1 << 7) +#define GOSSIP_FLOW_DEBUG ((__u64)1 << 8) +#define GOSSIP_BMI_DEBUG_GM_MEM ((__u64)1 << 9) +#define GOSSIP_REQUEST_DEBUG ((__u64)1 << 10) +#define GOSSIP_FLOW_PROTO_DEBUG ((__u64)1 << 11) +#define GOSSIP_NCACHE_DEBUG ((__u64)1 << 12) +#define GOSSIP_CLIENT_DEBUG ((__u64)1 << 13) +#define GOSSIP_REQ_SCHED_DEBUG ((__u64)1 << 14) +#define GOSSIP_ACACHE_DEBUG ((__u64)1 << 15) +#define GOSSIP_TROVE_DEBUG ((__u64)1 << 16) +#define GOSSIP_TROVE_OP_DEBUG ((__u64)1 << 17) +#define GOSSIP_DIST_DEBUG ((__u64)1 << 18) +#define GOSSIP_BMI_DEBUG_IB ((__u64)1 << 19) +#define GOSSIP_DBPF_ATTRCACHE_DEBUG ((__u64)1 << 20) +#define GOSSIP_MMAP_RCACHE_DEBUG ((__u64)1 << 21) +#define GOSSIP_LOOKUP_DEBUG ((__u64)1 << 22) +#define GOSSIP_REMOVE_DEBUG ((__u64)1 << 23) +#define GOSSIP_GETATTR_DEBUG ((__u64)1 << 24) +#define GOSSIP_READDIR_DEBUG ((__u64)1 << 25) +#define GOSSIP_IO_DEBUG ((__u64)1 << 26) +#define GOSSIP_DBPF_OPEN_CACHE_DEBUG ((__u64)1 << 27) +#define GOSSIP_PERMISSIONS_DEBUG ((__u64)1 << 28) +#define GOSSIP_CANCEL_DEBUG ((__u64)1 << 29) +#define GOSSIP_MSGPAIR_DEBUG ((__u64)1 << 30) +#define GOSSIP_CLIENTCORE_DEBUG ((__u64)1 << 31) +#define GOSSIP_CLIENTCORE_TIMING_DEBUG ((__u64)1 << 32) +#define GOSSIP_SETATTR_DEBUG ((__u64)1 << 33) +#define GOSSIP_MKDIR_DEBUG ((__u64)1 << 34) +#define GOSSIP_VARSTRIP_DEBUG ((__u64)1 << 35) +#define GOSSIP_GETEATTR_DEBUG ((__u64)1 << 36) +#define GOSSIP_SETEATTR_DEBUG ((__u64)1 << 37) +#define GOSSIP_ENDECODE_DEBUG ((__u64)1 << 38) +#define GOSSIP_DELEATTR_DEBUG ((__u64)1 << 39) +#define GOSSIP_ACCESS_DEBUG ((__u64)1 << 40) +#define GOSSIP_ACCESS_DETAIL_DEBUG ((__u64)1 << 41) +#define GOSSIP_LISTEATTR_DEBUG ((__u64)1 << 42) +#define GOSSIP_PERFCOUNTER_DEBUG ((__u64)1 << 43) +#define GOSSIP_STATE_MACHINE_DEBUG ((__u64)1 << 44) +#define GOSSIP_DBPF_KEYVAL_DEBUG ((__u64)1 << 45) +#define GOSSIP_LISTATTR_DEBUG ((__u64)1 << 46) +#define GOSSIP_DBPF_COALESCE_DEBUG ((__u64)1 << 47) +#define GOSSIP_ACCESS_HOSTNAMES ((__u64)1 << 48) +#define GOSSIP_FSCK_DEBUG ((__u64)1 << 49) +#define GOSSIP_BMI_DEBUG_MX ((__u64)1 << 50) +#define GOSSIP_BSTREAM_DEBUG ((__u64)1 << 51) +#define GOSSIP_BMI_DEBUG_PORTALS ((__u64)1 << 52) +#define GOSSIP_USER_DEV_DEBUG ((__u64)1 << 53) +#define GOSSIP_DIRECTIO_DEBUG ((__u64)1 << 54) +#define GOSSIP_MGMT_DEBUG ((__u64)1 << 55) +#define GOSSIP_MIRROR_DEBUG ((__u64)1 << 56) +#define GOSSIP_WIN_CLIENT_DEBUG ((__u64)1 << 57) +#define GOSSIP_SECURITY_DEBUG ((__u64)1 << 58) +#define GOSSIP_USRINT_DEBUG ((__u64)1 << 59) +#define GOSSIP_RCACHE_DEBUG ((__u64)1 << 60) +#define GOSSIP_SECCACHE_DEBUG ((__u64)1 << 61) + +#define GOSSIP_BMI_DEBUG_ALL ((__u64) (GOSSIP_BMI_DEBUG_TCP + \ + GOSSIP_BMI_DEBUG_CONTROL + \ + GOSSIP_BMI_DEBUG_GM + \ + GOSSIP_BMI_DEBUG_OFFSETS + \ + GOSSIP_BMI_DEBUG_IB + \ + GOSSIP_BMI_DEBUG_MX + \ + GOSSIP_BMI_DEBUG_PORTALS)) + +const char *ORANGEFS_debug_get_next_debug_keyword(int position); + +#define GOSSIP_SUPER_DEBUG ((__u64)1 << 0) +#define GOSSIP_INODE_DEBUG ((__u64)1 << 1) +#define GOSSIP_FILE_DEBUG ((__u64)1 << 2) +#define GOSSIP_DIR_DEBUG ((__u64)1 << 3) +#define GOSSIP_UTILS_DEBUG ((__u64)1 << 4) +#define GOSSIP_WAIT_DEBUG ((__u64)1 << 5) +#define GOSSIP_ACL_DEBUG ((__u64)1 << 6) +#define GOSSIP_DCACHE_DEBUG ((__u64)1 << 7) +#define GOSSIP_DEV_DEBUG ((__u64)1 << 8) +#define GOSSIP_NAME_DEBUG ((__u64)1 << 9) +#define GOSSIP_BUFMAP_DEBUG ((__u64)1 << 10) +#define GOSSIP_CACHE_DEBUG ((__u64)1 << 11) +#define GOSSIP_DEBUGFS_DEBUG ((__u64)1 << 12) +#define GOSSIP_XATTR_DEBUG ((__u64)1 << 13) +#define GOSSIP_INIT_DEBUG ((__u64)1 << 14) +#define GOSSIP_SYSFS_DEBUG ((__u64)1 << 15) + +#define GOSSIP_MAX_NR 16 +#define GOSSIP_MAX_DEBUG (((__u64)1 << GOSSIP_MAX_NR) - 1) + +/*function prototypes*/ +__u64 ORANGEFS_kmod_eventlog_to_mask(const char *event_logging); +__u64 ORANGEFS_debug_eventlog_to_mask(const char *event_logging); +char *ORANGEFS_debug_mask_to_eventlog(__u64 mask); +char *ORANGEFS_kmod_mask_to_eventlog(__u64 mask); + +/* a private internal type */ +struct __keyword_mask_s { + const char *keyword; + __u64 mask_val; +}; + +#define __DEBUG_ALL ((__u64) -1) + +/* map all config keywords to pvfs2 debug masks here */ +static struct __keyword_mask_s s_keyword_mask_map[] = { + /* Log trove debugging info. Same as 'trove'. */ + {"storage", GOSSIP_TROVE_DEBUG}, + /* Log trove debugging info. Same as 'storage'. */ + {"trove", GOSSIP_TROVE_DEBUG}, + /* Log trove operations. */ + {"trove_op", GOSSIP_TROVE_OP_DEBUG}, + /* Log network debug info. */ + {"network", GOSSIP_BMI_DEBUG_ALL}, + /* Log server info, including new operations. */ + {"server", GOSSIP_SERVER_DEBUG}, + /* Log client sysint info. This is only useful for the client. */ + {"client", GOSSIP_CLIENT_DEBUG}, + /* Debug the varstrip distribution */ + {"varstrip", GOSSIP_VARSTRIP_DEBUG}, + /* Log job info */ + {"job", GOSSIP_JOB_DEBUG}, + /* Debug PINT_process_request calls. EXTREMELY verbose! */ + {"request", GOSSIP_REQUEST_DEBUG}, + /* Log request scheduler events */ + {"reqsched", GOSSIP_REQ_SCHED_DEBUG}, + /* Log the flow protocol events, including flowproto_multiqueue */ + {"flowproto", GOSSIP_FLOW_PROTO_DEBUG}, + /* Log flow calls */ + {"flow", GOSSIP_FLOW_DEBUG}, + /* Debug the client name cache. Only useful on the client. */ + {"ncache", GOSSIP_NCACHE_DEBUG}, + /* Debug read-ahead cache events. Only useful on the client. */ + {"mmaprcache", GOSSIP_MMAP_RCACHE_DEBUG}, + /* Debug the attribute cache. Only useful on the client. */ + {"acache", GOSSIP_ACACHE_DEBUG}, + /* Log/Debug distribution calls */ + {"distribution", GOSSIP_DIST_DEBUG}, + /* Debug the server-side dbpf attribute cache */ + {"dbpfattrcache", GOSSIP_DBPF_ATTRCACHE_DEBUG}, + /* Debug the client lookup state machine. */ + {"lookup", GOSSIP_LOOKUP_DEBUG}, + /* Debug the client remove state macine. */ + {"remove", GOSSIP_REMOVE_DEBUG}, + /* Debug the server getattr state machine. */ + {"getattr", GOSSIP_GETATTR_DEBUG}, + /* Debug the server setattr state machine. */ + {"setattr", GOSSIP_SETATTR_DEBUG}, + /* vectored getattr server state machine */ + {"listattr", GOSSIP_LISTATTR_DEBUG}, + /* Debug the client and server get ext attributes SM. */ + {"geteattr", GOSSIP_GETEATTR_DEBUG}, + /* Debug the client and server set ext attributes SM. */ + {"seteattr", GOSSIP_SETEATTR_DEBUG}, + /* Debug the readdir operation (client and server) */ + {"readdir", GOSSIP_READDIR_DEBUG}, + /* Debug the mkdir operation (server only) */ + {"mkdir", GOSSIP_MKDIR_DEBUG}, + /* + * Debug the io operation (reads and writes) + * for both the client and server. + */ + {"io", GOSSIP_IO_DEBUG}, + /* Debug the server's open file descriptor cache */ + {"open_cache", GOSSIP_DBPF_OPEN_CACHE_DEBUG}, + /* Debug permissions checking on the server */ + {"permissions", GOSSIP_PERMISSIONS_DEBUG}, + /* Debug the cancel operation */ + {"cancel", GOSSIP_CANCEL_DEBUG}, + /* Debug the msgpair state machine */ + {"msgpair", GOSSIP_MSGPAIR_DEBUG}, + /* Debug the client core app */ + {"clientcore", GOSSIP_CLIENTCORE_DEBUG}, + /* Debug the client timing state machines (job timeout, etc.) */ + {"clientcore_timing", GOSSIP_CLIENTCORE_TIMING_DEBUG}, + /* network encoding */ + {"endecode", GOSSIP_ENDECODE_DEBUG}, + /* Show server file (metadata) accesses (both modify and read-only). */ + {"access", GOSSIP_ACCESS_DEBUG}, + /* Show more detailed server file accesses */ + {"access_detail", GOSSIP_ACCESS_DETAIL_DEBUG}, + /* Debug the listeattr operation */ + {"listeattr", GOSSIP_LISTEATTR_DEBUG}, + /* Debug the state machine management code */ + {"sm", GOSSIP_STATE_MACHINE_DEBUG}, + /* Debug the metadata dbpf keyval functions */ + {"keyval", GOSSIP_DBPF_KEYVAL_DEBUG}, + /* Debug the metadata sync coalescing code */ + {"coalesce", GOSSIP_DBPF_COALESCE_DEBUG}, + /* Display the hostnames instead of IP addrs in debug output */ + {"access_hostnames", GOSSIP_ACCESS_HOSTNAMES}, + /* Show the client device events */ + {"user_dev", GOSSIP_USER_DEV_DEBUG}, + /* Debug the fsck tool */ + {"fsck", GOSSIP_FSCK_DEBUG}, + /* Debug the bstream code */ + {"bstream", GOSSIP_BSTREAM_DEBUG}, + /* Debug trove in direct io mode */ + {"directio", GOSSIP_DIRECTIO_DEBUG}, + /* Debug direct io thread management */ + {"mgmt", GOSSIP_MGMT_DEBUG}, + /* Debug mirroring process */ + {"mirror", GOSSIP_MIRROR_DEBUG}, + /* Windows client */ + {"win_client", GOSSIP_WIN_CLIENT_DEBUG}, + /* Debug robust security code */ + {"security", GOSSIP_SECURITY_DEBUG}, + /* Capability Cache */ + {"seccache", GOSSIP_SECCACHE_DEBUG}, + /* Client User Interface */ + {"usrint", GOSSIP_USRINT_DEBUG}, + /* rcache */ + {"rcache", GOSSIP_RCACHE_DEBUG}, + /* Everything except the periodic events. Useful for debugging */ + {"verbose", + (__DEBUG_ALL & + ~(GOSSIP_PERFCOUNTER_DEBUG | GOSSIP_STATE_MACHINE_DEBUG | + GOSSIP_ENDECODE_DEBUG | GOSSIP_USER_DEV_DEBUG)) + }, + /* No debug output */ + {"none", GOSSIP_NO_DEBUG}, + /* Everything */ + {"all", __DEBUG_ALL} +}; + +#undef __DEBUG_ALL + +/* + * Map all kmod keywords to kmod debug masks here. Keep this + * structure "packed": + * + * "all" is always last... + * + * keyword mask_val index + * foo 1 0 + * bar 2 1 + * baz 4 2 + * qux 8 3 + * . . . + */ +static struct __keyword_mask_s s_kmod_keyword_mask_map[] = { + {"super", GOSSIP_SUPER_DEBUG}, + {"inode", GOSSIP_INODE_DEBUG}, + {"file", GOSSIP_FILE_DEBUG}, + {"dir", GOSSIP_DIR_DEBUG}, + {"utils", GOSSIP_UTILS_DEBUG}, + {"wait", GOSSIP_WAIT_DEBUG}, + {"acl", GOSSIP_ACL_DEBUG}, + {"dcache", GOSSIP_DCACHE_DEBUG}, + {"dev", GOSSIP_DEV_DEBUG}, + {"name", GOSSIP_NAME_DEBUG}, + {"bufmap", GOSSIP_BUFMAP_DEBUG}, + {"cache", GOSSIP_CACHE_DEBUG}, + {"debugfs", GOSSIP_DEBUGFS_DEBUG}, + {"xattr", GOSSIP_XATTR_DEBUG}, + {"init", GOSSIP_INIT_DEBUG}, + {"sysfs", GOSSIP_SYSFS_DEBUG}, + {"none", GOSSIP_NO_DEBUG}, + {"all", GOSSIP_MAX_DEBUG} +}; + +static const int num_kmod_keyword_mask_map = (int) + (sizeof(s_kmod_keyword_mask_map) / sizeof(struct __keyword_mask_s)); + +static const int num_keyword_mask_map = (int) + (sizeof(s_keyword_mask_map) / sizeof(struct __keyword_mask_s)); + +#endif /* __ORANGEFS_DEBUG_H */ diff --git a/fs/orangefs/orangefs-debugfs.c b/fs/orangefs/orangefs-debugfs.c new file mode 100644 index 000000000000..7319f1a2ecb8 --- /dev/null +++ b/fs/orangefs/orangefs-debugfs.c @@ -0,0 +1,458 @@ +/* + * What: /sys/kernel/debug/orangefs/debug-help + * Date: June 2015 + * Contact: Mike Marshall + * Description: + * List of client and kernel debug keywords. + * + * + * What: /sys/kernel/debug/orangefs/client-debug + * Date: June 2015 + * Contact: Mike Marshall + * Description: + * Debug setting for "the client", the userspace + * helper for the kernel module. + * + * + * What: /sys/kernel/debug/orangefs/kernel-debug + * Date: June 2015 + * Contact: Mike Marshall + * Description: + * Debug setting for the orangefs kernel module. + * + * Any of the keywords, or comma-separated lists + * of keywords, from debug-help can be catted to + * client-debug or kernel-debug. + * + * "none", "all" and "verbose" are special keywords + * for client-debug. Setting client-debug to "all" + * is kind of like trying to drink water from a + * fire hose, "verbose" triggers most of the same + * output except for the constant flow of output + * from the main wait loop. + * + * "none" and "all" are similar settings for kernel-debug + * no need for a "verbose". + */ +#include +#include + +#include + +#include "orangefs-debugfs.h" +#include "protocol.h" +#include "orangefs-kernel.h" + +static int orangefs_debug_disabled = 1; + +static int orangefs_debug_help_open(struct inode *, struct file *); + +const struct file_operations debug_help_fops = { + .open = orangefs_debug_help_open, + .read = seq_read, + .release = seq_release, + .llseek = seq_lseek, +}; + +static void *help_start(struct seq_file *, loff_t *); +static void *help_next(struct seq_file *, void *, loff_t *); +static void help_stop(struct seq_file *, void *); +static int help_show(struct seq_file *, void *); + +static const struct seq_operations help_debug_ops = { + .start = help_start, + .next = help_next, + .stop = help_stop, + .show = help_show, +}; + +/* + * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and + * ORANGEFS_KMOD_DEBUG_FILE. + */ +static DEFINE_MUTEX(orangefs_debug_lock); + +int orangefs_debug_open(struct inode *, struct file *); + +static ssize_t orangefs_debug_read(struct file *, + char __user *, + size_t, + loff_t *); + +static ssize_t orangefs_debug_write(struct file *, + const char __user *, + size_t, + loff_t *); + +static const struct file_operations kernel_debug_fops = { + .open = orangefs_debug_open, + .read = orangefs_debug_read, + .write = orangefs_debug_write, + .llseek = generic_file_llseek, +}; + +/* + * initialize kmod debug operations, create orangefs debugfs dir and + * ORANGEFS_KMOD_DEBUG_HELP_FILE. + */ +int orangefs_debugfs_init(void) +{ + + int rc = -ENOMEM; + + debug_dir = debugfs_create_dir("orangefs", NULL); + if (!debug_dir) + goto out; + + help_file_dentry = debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE, + 0444, + debug_dir, + debug_help_string, + &debug_help_fops); + if (!help_file_dentry) + goto out; + + orangefs_debug_disabled = 0; + rc = 0; + +out: + if (rc) + orangefs_debugfs_cleanup(); + + return rc; +} + +void orangefs_debugfs_cleanup(void) +{ + debugfs_remove_recursive(debug_dir); +} + +/* open ORANGEFS_KMOD_DEBUG_HELP_FILE */ +static int orangefs_debug_help_open(struct inode *inode, struct file *file) +{ + int rc = -ENODEV; + int ret; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "orangefs_debug_help_open: start\n"); + + if (orangefs_debug_disabled) + goto out; + + ret = seq_open(file, &help_debug_ops); + if (ret) + goto out; + + ((struct seq_file *)(file->private_data))->private = inode->i_private; + + rc = 0; + +out: + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "orangefs_debug_help_open: rc:%d:\n", + rc); + return rc; +} + +/* + * I think start always gets called again after stop. Start + * needs to return NULL when it is done. The whole "payload" + * in this case is a single (long) string, so by the second + * time we get to start (pos = 1), we're done. + */ +static void *help_start(struct seq_file *m, loff_t *pos) +{ + void *payload = NULL; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n"); + + if (*pos == 0) + payload = m->private; + + return payload; +} + +static void *help_next(struct seq_file *m, void *v, loff_t *pos) +{ + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n"); + + return NULL; +} + +static void help_stop(struct seq_file *m, void *p) +{ + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n"); +} + +static int help_show(struct seq_file *m, void *v) +{ + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n"); + + seq_puts(m, v); + + return 0; +} + +/* + * initialize the kernel-debug file. + */ +int orangefs_kernel_debug_init(void) +{ + + int rc = -ENOMEM; + struct dentry *ret; + char *k_buffer = NULL; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__); + + k_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); + if (!k_buffer) + goto out; + + if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) { + strcpy(k_buffer, kernel_debug_string); + strcat(k_buffer, "\n"); + } else { + strcpy(k_buffer, "none\n"); + pr_info("%s: overflow 1!\n", __func__); + } + + ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE, + 0444, + debug_dir, + k_buffer, + &kernel_debug_fops); + if (!ret) { + pr_info("%s: failed to create %s.\n", + __func__, + ORANGEFS_KMOD_DEBUG_FILE); + goto out; + } + + rc = 0; + +out: + if (rc) + orangefs_debugfs_cleanup(); + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc); + return rc; +} + +/* + * initialize the client-debug file. + */ +int orangefs_client_debug_init(void) +{ + + int rc = -ENOMEM; + char *c_buffer = NULL; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__); + + c_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); + if (!c_buffer) + goto out; + + if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) { + strcpy(c_buffer, client_debug_string); + strcat(c_buffer, "\n"); + } else { + strcpy(c_buffer, "none\n"); + pr_info("%s: overflow! 2\n", __func__); + } + + client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE, + 0444, + debug_dir, + c_buffer, + &kernel_debug_fops); + if (!client_debug_dentry) { + pr_info("%s: failed to create %s.\n", + __func__, + ORANGEFS_CLIENT_DEBUG_FILE); + goto out; + } + + rc = 0; + +out: + if (rc) + orangefs_debugfs_cleanup(); + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc); + return rc; +} + +/* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/ +int orangefs_debug_open(struct inode *inode, struct file *file) +{ + int rc = -ENODEV; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "%s: orangefs_debug_disabled: %d\n", + __func__, + orangefs_debug_disabled); + + if (orangefs_debug_disabled) + goto out; + + rc = 0; + mutex_lock(&orangefs_debug_lock); + file->private_data = inode->i_private; + mutex_unlock(&orangefs_debug_lock); + +out: + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "orangefs_debug_open: rc: %d\n", + rc); + return rc; +} + +static ssize_t orangefs_debug_read(struct file *file, + char __user *ubuf, + size_t count, + loff_t *ppos) +{ + char *buf; + int sprintf_ret; + ssize_t read_ret = -ENOMEM; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n"); + + buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); + if (!buf) + goto out; + + mutex_lock(&orangefs_debug_lock); + sprintf_ret = sprintf(buf, "%s", (char *)file->private_data); + mutex_unlock(&orangefs_debug_lock); + + read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret); + + kfree(buf); + +out: + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "orangefs_debug_read: ret: %zu\n", + read_ret); + + return read_ret; +} + +static ssize_t orangefs_debug_write(struct file *file, + const char __user *ubuf, + size_t count, + loff_t *ppos) +{ + char *buf; + int rc = -EFAULT; + size_t silly = 0; + char *debug_string; + struct orangefs_kernel_op_s *new_op = NULL; + struct client_debug_mask c_mask = { NULL, 0, 0 }; + + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "orangefs_debug_write: %s\n", + file->f_path.dentry->d_name.name); + + /* + * Thwart users who try to jamb a ridiculous number + * of bytes into the debug file... + */ + if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) { + silly = count; + count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1; + } + + buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); + if (!buf) + goto out; + memset(buf, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); + + if (copy_from_user(buf, ubuf, count - 1)) { + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "%s: copy_from_user failed!\n", + __func__); + goto out; + } + + /* + * Map the keyword string from userspace into a valid debug mask. + * The mapping process involves mapping the human-inputted string + * into a valid mask, and then rebuilding the string from the + * verified valid mask. + * + * A service operation is required to set a new client-side + * debug mask. + */ + if (!strcmp(file->f_path.dentry->d_name.name, + ORANGEFS_KMOD_DEBUG_FILE)) { + debug_string_to_mask(buf, &gossip_debug_mask, 0); + debug_mask_to_string(&gossip_debug_mask, 0); + debug_string = kernel_debug_string; + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "New kernel debug string is %s\n", + kernel_debug_string); + } else { + /* Can't reset client debug mask if client is not running. */ + if (is_daemon_in_service()) { + pr_info("%s: Client not running :%d:\n", + __func__, + is_daemon_in_service()); + goto out; + } + + debug_string_to_mask(buf, &c_mask, 1); + debug_mask_to_string(&c_mask, 1); + debug_string = client_debug_string; + + new_op = op_alloc(ORANGEFS_VFS_OP_PARAM); + if (!new_op) { + pr_info("%s: op_alloc failed!\n", __func__); + goto out; + } + + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES; + new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET; + memset(new_op->upcall.req.param.s_value, + 0, + ORANGEFS_MAX_DEBUG_STRING_LEN); + sprintf(new_op->upcall.req.param.s_value, + "%llx %llx\n", + c_mask.mask1, + c_mask.mask2); + + /* service_operation returns 0 on success... */ + rc = service_operation(new_op, + "orangefs_param", + ORANGEFS_OP_INTERRUPTIBLE); + + if (rc) + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "%s: service_operation failed! rc:%d:\n", + __func__, + rc); + + op_release(new_op); + } + + mutex_lock(&orangefs_debug_lock); + memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); + sprintf((char *)file->f_inode->i_private, "%s\n", debug_string); + mutex_unlock(&orangefs_debug_lock); + + *ppos += count; + if (silly) + rc = silly; + else + rc = count; + +out: + gossip_debug(GOSSIP_DEBUGFS_DEBUG, + "orangefs_debug_write: rc: %d\n", + rc); + kfree(buf); + return rc; +} diff --git a/fs/orangefs/orangefs-debugfs.h b/fs/orangefs/orangefs-debugfs.h new file mode 100644 index 000000000000..e4828c0e3ef9 --- /dev/null +++ b/fs/orangefs/orangefs-debugfs.h @@ -0,0 +1,3 @@ +int orangefs_debugfs_init(void); +int orangefs_kernel_debug_init(void); +void orangefs_debugfs_cleanup(void); diff --git a/fs/orangefs/orangefs-dev-proto.h b/fs/orangefs/orangefs-dev-proto.h new file mode 100644 index 000000000000..dc1951dd7045 --- /dev/null +++ b/fs/orangefs/orangefs-dev-proto.h @@ -0,0 +1,85 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +#ifndef _ORANGEFS_DEV_PROTO_H +#define _ORANGEFS_DEV_PROTO_H + +/* + * types and constants shared between user space and kernel space for + * device interaction using a common protocol + */ + +/* + * valid orangefs kernel operation types + */ +#define ORANGEFS_VFS_OP_INVALID 0xFF000000 +#define ORANGEFS_VFS_OP_FILE_IO 0xFF000001 +#define ORANGEFS_VFS_OP_LOOKUP 0xFF000002 +#define ORANGEFS_VFS_OP_CREATE 0xFF000003 +#define ORANGEFS_VFS_OP_GETATTR 0xFF000004 +#define ORANGEFS_VFS_OP_REMOVE 0xFF000005 +#define ORANGEFS_VFS_OP_MKDIR 0xFF000006 +#define ORANGEFS_VFS_OP_READDIR 0xFF000007 +#define ORANGEFS_VFS_OP_SETATTR 0xFF000008 +#define ORANGEFS_VFS_OP_SYMLINK 0xFF000009 +#define ORANGEFS_VFS_OP_RENAME 0xFF00000A +#define ORANGEFS_VFS_OP_STATFS 0xFF00000B +#define ORANGEFS_VFS_OP_TRUNCATE 0xFF00000C +#define ORANGEFS_VFS_OP_MMAP_RA_FLUSH 0xFF00000D +#define ORANGEFS_VFS_OP_FS_MOUNT 0xFF00000E +#define ORANGEFS_VFS_OP_FS_UMOUNT 0xFF00000F +#define ORANGEFS_VFS_OP_GETXATTR 0xFF000010 +#define ORANGEFS_VFS_OP_SETXATTR 0xFF000011 +#define ORANGEFS_VFS_OP_LISTXATTR 0xFF000012 +#define ORANGEFS_VFS_OP_REMOVEXATTR 0xFF000013 +#define ORANGEFS_VFS_OP_PARAM 0xFF000014 +#define ORANGEFS_VFS_OP_PERF_COUNT 0xFF000015 +#define ORANGEFS_VFS_OP_CANCEL 0xFF00EE00 +#define ORANGEFS_VFS_OP_FSYNC 0xFF00EE01 +#define ORANGEFS_VFS_OP_FSKEY 0xFF00EE02 +#define ORANGEFS_VFS_OP_READDIRPLUS 0xFF00EE03 + +/* + * Misc constants. Please retain them as multiples of 8! + * Otherwise 32-64 bit interactions will be messed up :) + */ +#define ORANGEFS_NAME_LEN 0x00000100 +#define ORANGEFS_MAX_DEBUG_STRING_LEN 0x00000400 +#define ORANGEFS_MAX_DEBUG_ARRAY_LEN 0x00000800 + +/* + * MAX_DIRENT_COUNT cannot be larger than ORANGEFS_REQ_LIMIT_LISTATTR. + * The value of ORANGEFS_REQ_LIMIT_LISTATTR has been changed from 113 to 60 + * to accomodate an attribute object with mirrored handles. + * MAX_DIRENT_COUNT is replaced by MAX_DIRENT_COUNT_READDIR and + * MAX_DIRENT_COUNT_READDIRPLUS, since readdir doesn't trigger a listattr + * but readdirplus might. +*/ +#define MAX_DIRENT_COUNT_READDIR 0x00000060 +#define MAX_DIRENT_COUNT_READDIRPLUS 0x0000003C + +#include "upcall.h" +#include "downcall.h" + +/* + * These macros differ from proto macros in that they don't do any + * byte-swappings and are used to ensure that kernel-clientcore interactions + * don't cause any unaligned accesses etc on 64 bit machines + */ +#ifndef roundup4 +#define roundup4(x) (((x)+3) & ~3) +#endif + +#ifndef roundup8 +#define roundup8(x) (((x)+7) & ~7) +#endif + +struct read_write_x { + __s64 off; + __s64 len; +}; + +#endif diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h new file mode 100644 index 000000000000..840872389fc5 --- /dev/null +++ b/fs/orangefs/orangefs-kernel.h @@ -0,0 +1,819 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +/* + * The ORANGEFS Linux kernel support allows ORANGEFS volumes to be mounted and + * accessed through the Linux VFS (i.e. using standard I/O system calls). + * This support is only needed on clients that wish to mount the file system. + * + */ + +/* + * Declarations and macros for the ORANGEFS Linux kernel support. + */ + +#ifndef __ORANGEFSKERNEL_H +#define __ORANGEFSKERNEL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "orangefs-dev-proto.h" + +#ifdef ORANGEFS_KERNEL_DEBUG +#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS 10 +#else +#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS 20 +#endif + +#define ORANGEFS_BUFMAP_WAIT_TIMEOUT_SECS 30 + +#define ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS 900 /* 15 minutes */ + +#define ORANGEFS_REQDEVICE_NAME "pvfs2-req" + +#define ORANGEFS_DEVREQ_MAGIC 0x20030529 +#define ORANGEFS_LINK_MAX 0x000000FF +#define ORANGEFS_PURGE_RETRY_COUNT 0x00000005 +#define ORANGEFS_SEEK_END 0x00000002 +#define ORANGEFS_MAX_NUM_OPTIONS 0x00000004 +#define ORANGEFS_MAX_MOUNT_OPT_LEN 0x00000080 +#define ORANGEFS_MAX_FSKEY_LEN 64 + +#define MAX_DEV_REQ_UPSIZE (2*sizeof(__s32) + \ +sizeof(__u64) + sizeof(struct orangefs_upcall_s)) +#define MAX_DEV_REQ_DOWNSIZE (2*sizeof(__s32) + \ +sizeof(__u64) + sizeof(struct orangefs_downcall_s)) + +#define BITS_PER_LONG_DIV_8 (BITS_PER_LONG >> 3) + +/* borrowed from irda.h */ +#ifndef MSECS_TO_JIFFIES +#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000) +#endif + +#define MAX_ALIGNED_DEV_REQ_UPSIZE \ + (MAX_DEV_REQ_UPSIZE + \ + ((((MAX_DEV_REQ_UPSIZE / \ + (BITS_PER_LONG_DIV_8)) * \ + (BITS_PER_LONG_DIV_8)) + \ + (BITS_PER_LONG_DIV_8)) - \ + MAX_DEV_REQ_UPSIZE)) + +#define MAX_ALIGNED_DEV_REQ_DOWNSIZE \ + (MAX_DEV_REQ_DOWNSIZE + \ + ((((MAX_DEV_REQ_DOWNSIZE / \ + (BITS_PER_LONG_DIV_8)) * \ + (BITS_PER_LONG_DIV_8)) + \ + (BITS_PER_LONG_DIV_8)) - \ + MAX_DEV_REQ_DOWNSIZE)) + +/* + * valid orangefs kernel operation states + * + * unknown - op was just initialized + * waiting - op is on request_list (upward bound) + * inprogr - op is in progress (waiting for downcall) + * serviced - op has matching downcall; ok + * purged - op has to start a timer since client-core + * exited uncleanly before servicing op + */ +enum orangefs_vfs_op_states { + OP_VFS_STATE_UNKNOWN = 0, + OP_VFS_STATE_WAITING = 1, + OP_VFS_STATE_INPROGR = 2, + OP_VFS_STATE_SERVICED = 4, + OP_VFS_STATE_PURGED = 8, +}; + +#define set_op_state_waiting(op) ((op)->op_state = OP_VFS_STATE_WAITING) +#define set_op_state_inprogress(op) ((op)->op_state = OP_VFS_STATE_INPROGR) +#define set_op_state_serviced(op) ((op)->op_state = OP_VFS_STATE_SERVICED) +#define set_op_state_purged(op) ((op)->op_state |= OP_VFS_STATE_PURGED) + +#define op_state_waiting(op) ((op)->op_state & OP_VFS_STATE_WAITING) +#define op_state_in_progress(op) ((op)->op_state & OP_VFS_STATE_INPROGR) +#define op_state_serviced(op) ((op)->op_state & OP_VFS_STATE_SERVICED) +#define op_state_purged(op) ((op)->op_state & OP_VFS_STATE_PURGED) + +#define get_op(op) \ + do { \ + atomic_inc(&(op)->aio_ref_count); \ + gossip_debug(GOSSIP_DEV_DEBUG, \ + "(get) Alloced OP (%p:%llu)\n", \ + op, \ + llu((op)->tag)); \ + } while (0) + +#define put_op(op) \ + do { \ + if (atomic_sub_and_test(1, &(op)->aio_ref_count) == 1) { \ + gossip_debug(GOSSIP_DEV_DEBUG, \ + "(put) Releasing OP (%p:%llu)\n", \ + op, \ + llu((op)->tag)); \ + op_release(op); \ + } \ + } while (0) + +#define op_wait(op) (atomic_read(&(op)->aio_ref_count) <= 2 ? 0 : 1) + +/* + * Defines for controlling whether I/O upcalls are for async or sync operations + */ +enum ORANGEFS_async_io_type { + ORANGEFS_VFS_SYNC_IO = 0, + ORANGEFS_VFS_ASYNC_IO = 1, +}; + +/* + * An array of client_debug_mask will be built to hold debug keyword/mask + * values fetched from userspace. + */ +struct client_debug_mask { + char *keyword; + __u64 mask1; + __u64 mask2; +}; + +/* + * orangefs kernel memory related flags + */ + +#if ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB)) +#define ORANGEFS_CACHE_CREATE_FLAGS SLAB_RED_ZONE +#else +#define ORANGEFS_CACHE_CREATE_FLAGS 0 +#endif /* ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB)) */ + +#define ORANGEFS_CACHE_ALLOC_FLAGS (GFP_KERNEL) +#define ORANGEFS_GFP_FLAGS (GFP_KERNEL) +#define ORANGEFS_BUFMAP_GFP_FLAGS (GFP_KERNEL) + +/* orangefs xattr and acl related defines */ +#define ORANGEFS_XATTR_INDEX_POSIX_ACL_ACCESS 1 +#define ORANGEFS_XATTR_INDEX_POSIX_ACL_DEFAULT 2 +#define ORANGEFS_XATTR_INDEX_TRUSTED 3 +#define ORANGEFS_XATTR_INDEX_DEFAULT 4 + +#if 0 +#ifndef POSIX_ACL_XATTR_ACCESS +#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" +#endif +#ifndef POSIX_ACL_XATTR_DEFAULT +#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" +#endif +#endif + +#define ORANGEFS_XATTR_NAME_ACL_ACCESS POSIX_ACL_XATTR_ACCESS +#define ORANGEFS_XATTR_NAME_ACL_DEFAULT POSIX_ACL_XATTR_DEFAULT +#define ORANGEFS_XATTR_NAME_TRUSTED_PREFIX "trusted." +#define ORANGEFS_XATTR_NAME_DEFAULT_PREFIX "" + +/* these functions are defined in orangefs-utils.c */ +int orangefs_prepare_cdm_array(char *debug_array_string); +int orangefs_prepare_debugfs_help_string(int); + +/* defined in orangefs-debugfs.c */ +int orangefs_client_debug_init(void); + +void debug_string_to_mask(char *, void *, int); +void do_c_mask(int, char *, struct client_debug_mask **); +void do_k_mask(int, char *, __u64 **); + +void debug_mask_to_string(void *, int); +void do_k_string(void *, int); +void do_c_string(void *, int); +int check_amalgam_keyword(void *, int); +int keyword_is_amalgam(char *); + +/*these variables are defined in orangefs-mod.c */ +extern char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; +extern char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; +extern char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; +extern unsigned int kernel_mask_set_mod_init; + +extern int orangefs_init_acl(struct inode *inode, struct inode *dir); +extern const struct xattr_handler *orangefs_xattr_handlers[]; + +extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type); +extern int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type); + +/* + * Redefine xtvec structure so that we could move helper functions out of + * the define + */ +struct xtvec { + __kernel_off_t xtv_off; /* must be off_t */ + __kernel_size_t xtv_len; /* must be size_t */ +}; + +/* + * orangefs data structures + */ +struct orangefs_kernel_op_s { + enum orangefs_vfs_op_states op_state; + __u64 tag; + + /* + * Set uses_shared_memory to 1 if this operation uses shared memory. + * If true, then a retry on the op must also get a new shared memory + * buffer and re-populate it. + */ + int uses_shared_memory; + + struct orangefs_upcall_s upcall; + struct orangefs_downcall_s downcall; + + wait_queue_head_t waitq; + spinlock_t lock; + + int io_completed; + wait_queue_head_t io_completion_waitq; + + /* VFS aio fields */ + + /* used by the async I/O code to stash the orangefs_kiocb_s structure */ + void *priv; + + /* used again for the async I/O code for deallocation */ + atomic_t aio_ref_count; + + int attempts; + + struct list_head list; +}; + +/* per inode private orangefs info */ +struct orangefs_inode_s { + struct orangefs_object_kref refn; + char link_target[ORANGEFS_NAME_MAX]; + __s64 blksize; + /* + * Reading/Writing Extended attributes need to acquire the appropriate + * reader/writer semaphore on the orangefs_inode_s structure. + */ + struct rw_semaphore xattr_sem; + + struct inode vfs_inode; + sector_t last_failed_block_index_read; + + /* + * State of in-memory attributes not yet flushed to disk associated + * with this object + */ + unsigned long pinode_flags; + + /* All allocated orangefs_inode_s objects are chained to a list */ + struct list_head list; +}; + +#define P_ATIME_FLAG 0 +#define P_MTIME_FLAG 1 +#define P_CTIME_FLAG 2 +#define P_MODE_FLAG 3 + +#define ClearAtimeFlag(pinode) clear_bit(P_ATIME_FLAG, &(pinode)->pinode_flags) +#define SetAtimeFlag(pinode) set_bit(P_ATIME_FLAG, &(pinode)->pinode_flags) +#define AtimeFlag(pinode) test_bit(P_ATIME_FLAG, &(pinode)->pinode_flags) + +#define ClearMtimeFlag(pinode) clear_bit(P_MTIME_FLAG, &(pinode)->pinode_flags) +#define SetMtimeFlag(pinode) set_bit(P_MTIME_FLAG, &(pinode)->pinode_flags) +#define MtimeFlag(pinode) test_bit(P_MTIME_FLAG, &(pinode)->pinode_flags) + +#define ClearCtimeFlag(pinode) clear_bit(P_CTIME_FLAG, &(pinode)->pinode_flags) +#define SetCtimeFlag(pinode) set_bit(P_CTIME_FLAG, &(pinode)->pinode_flags) +#define CtimeFlag(pinode) test_bit(P_CTIME_FLAG, &(pinode)->pinode_flags) + +#define ClearModeFlag(pinode) clear_bit(P_MODE_FLAG, &(pinode)->pinode_flags) +#define SetModeFlag(pinode) set_bit(P_MODE_FLAG, &(pinode)->pinode_flags) +#define ModeFlag(pinode) test_bit(P_MODE_FLAG, &(pinode)->pinode_flags) + +/* per superblock private orangefs info */ +struct orangefs_sb_info_s { + struct orangefs_khandle root_khandle; + __s32 fs_id; + int id; + int flags; +#define ORANGEFS_OPT_INTR 0x01 +#define ORANGEFS_OPT_LOCAL_LOCK 0x02 + char devname[ORANGEFS_MAX_SERVER_ADDR_LEN]; + struct super_block *sb; + int mount_pending; + struct list_head list; +}; + +/* + * structure that holds the state of any async I/O operation issued + * through the VFS. Needed especially to handle cancellation requests + * or even completion notification so that the VFS client-side daemon + * can free up its vfs_request slots. + */ +struct orangefs_kiocb_s { + /* the pointer to the task that initiated the AIO */ + struct task_struct *tsk; + + /* pointer to the kiocb that kicked this operation */ + struct kiocb *kiocb; + + /* buffer index that was used for the I/O */ + struct orangefs_bufmap *bufmap; + int buffer_index; + + /* orangefs kernel operation type */ + struct orangefs_kernel_op_s *op; + + /* The user space buffers from/to which I/O is being staged */ + struct iovec *iov; + + /* number of elements in the iovector */ + unsigned long nr_segs; + + /* set to indicate the type of the operation */ + int rw; + + /* file offset */ + loff_t offset; + + /* and the count in bytes */ + size_t bytes_to_be_copied; + + ssize_t bytes_copied; + int needs_cleanup; +}; + +struct orangefs_stats { + unsigned long cache_hits; + unsigned long cache_misses; + unsigned long reads; + unsigned long writes; +}; + +extern struct orangefs_stats g_orangefs_stats; + +/* + * NOTE: See Documentation/filesystems/porting for information + * on implementing FOO_I and properly accessing fs private data + */ +static inline struct orangefs_inode_s *ORANGEFS_I(struct inode *inode) +{ + return container_of(inode, struct orangefs_inode_s, vfs_inode); +} + +static inline struct orangefs_sb_info_s *ORANGEFS_SB(struct super_block *sb) +{ + return (struct orangefs_sb_info_s *) sb->s_fs_info; +} + +/* ino_t descends from "unsigned long", 8 bytes, 64 bits. */ +static inline ino_t orangefs_khandle_to_ino(struct orangefs_khandle *khandle) +{ + union { + unsigned char u[8]; + __u64 ino; + } ihandle; + + ihandle.u[0] = khandle->u[0] ^ khandle->u[4]; + ihandle.u[1] = khandle->u[1] ^ khandle->u[5]; + ihandle.u[2] = khandle->u[2] ^ khandle->u[6]; + ihandle.u[3] = khandle->u[3] ^ khandle->u[7]; + ihandle.u[4] = khandle->u[12] ^ khandle->u[8]; + ihandle.u[5] = khandle->u[13] ^ khandle->u[9]; + ihandle.u[6] = khandle->u[14] ^ khandle->u[10]; + ihandle.u[7] = khandle->u[15] ^ khandle->u[11]; + + return ihandle.ino; +} + +static inline struct orangefs_khandle *get_khandle_from_ino(struct inode *inode) +{ + return &(ORANGEFS_I(inode)->refn.khandle); +} + +static inline __s32 get_fsid_from_ino(struct inode *inode) +{ + return ORANGEFS_I(inode)->refn.fs_id; +} + +static inline ino_t get_ino_from_khandle(struct inode *inode) +{ + struct orangefs_khandle *khandle; + ino_t ino; + + khandle = get_khandle_from_ino(inode); + ino = orangefs_khandle_to_ino(khandle); + return ino; +} + +static inline ino_t get_parent_ino_from_dentry(struct dentry *dentry) +{ + return get_ino_from_khandle(dentry->d_parent->d_inode); +} + +static inline int is_root_handle(struct inode *inode) +{ + gossip_debug(GOSSIP_DCACHE_DEBUG, + "%s: root handle: %pU, this handle: %pU:\n", + __func__, + &ORANGEFS_SB(inode->i_sb)->root_khandle, + get_khandle_from_ino(inode)); + + if (ORANGEFS_khandle_cmp(&(ORANGEFS_SB(inode->i_sb)->root_khandle), + get_khandle_from_ino(inode))) + return 0; + else + return 1; +} + +static inline int match_handle(struct orangefs_khandle resp_handle, + struct inode *inode) +{ + gossip_debug(GOSSIP_DCACHE_DEBUG, + "%s: one handle: %pU, another handle:%pU:\n", + __func__, + &resp_handle, + get_khandle_from_ino(inode)); + + if (ORANGEFS_khandle_cmp(&resp_handle, get_khandle_from_ino(inode))) + return 0; + else + return 1; +} + +/* + * defined in orangefs-cache.c + */ +int op_cache_initialize(void); +int op_cache_finalize(void); +struct orangefs_kernel_op_s *op_alloc(__s32 type); +char *get_opname_string(struct orangefs_kernel_op_s *new_op); +void op_release(struct orangefs_kernel_op_s *op); + +int dev_req_cache_initialize(void); +int dev_req_cache_finalize(void); +void *dev_req_alloc(void); +void dev_req_release(void *); + +int orangefs_inode_cache_initialize(void); +int orangefs_inode_cache_finalize(void); + +int kiocb_cache_initialize(void); +int kiocb_cache_finalize(void); +struct orangefs_kiocb_s *kiocb_alloc(void); +void kiocb_release(struct orangefs_kiocb_s *ptr); + +/* + * defined in orangefs-mod.c + */ +void purge_inprogress_ops(void); + +/* + * defined in waitqueue.c + */ +int wait_for_matching_downcall(struct orangefs_kernel_op_s *op); +int wait_for_cancellation_downcall(struct orangefs_kernel_op_s *op); +void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op); +void purge_waiting_ops(void); + +/* + * defined in super.c + */ +struct dentry *orangefs_mount(struct file_system_type *fst, + int flags, + const char *devname, + void *data); + +void orangefs_kill_sb(struct super_block *sb); +int orangefs_remount(struct super_block *sb); + +int fsid_key_table_initialize(void); +void fsid_key_table_finalize(void); + +/* + * defined in inode.c + */ +__u32 convert_to_orangefs_mask(unsigned long lite_mask); +struct inode *orangefs_new_inode(struct super_block *sb, + struct inode *dir, + int mode, + dev_t dev, + struct orangefs_object_kref *ref); + +int orangefs_setattr(struct dentry *dentry, struct iattr *iattr); + +int orangefs_getattr(struct vfsmount *mnt, + struct dentry *dentry, + struct kstat *kstat); + +/* + * defined in xattr.c + */ +int orangefs_setxattr(struct dentry *dentry, + const char *name, + const void *value, + size_t size, + int flags); + +ssize_t orangefs_getxattr(struct dentry *dentry, + const char *name, + void *buffer, + size_t size); + +ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size); + +/* + * defined in namei.c + */ +struct inode *orangefs_iget(struct super_block *sb, + struct orangefs_object_kref *ref); + +ssize_t orangefs_inode_read(struct inode *inode, + struct iov_iter *iter, + loff_t *offset, + loff_t readahead_size); + +/* + * defined in devorangefs-req.c + */ +int orangefs_dev_init(void); +void orangefs_dev_cleanup(void); +int is_daemon_in_service(void); +int fs_mount_pending(__s32 fsid); + +/* + * defined in orangefs-utils.c + */ +__s32 fsid_of_op(struct orangefs_kernel_op_s *op); + +int orangefs_flush_inode(struct inode *inode); + +ssize_t orangefs_inode_getxattr(struct inode *inode, + const char *prefix, + const char *name, + void *buffer, + size_t size); + +int orangefs_inode_setxattr(struct inode *inode, + const char *prefix, + const char *name, + const void *value, + size_t size, + int flags); + +int orangefs_inode_getattr(struct inode *inode, __u32 mask); + +int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr); + +void orangefs_op_initialize(struct orangefs_kernel_op_s *op); + +void orangefs_make_bad_inode(struct inode *inode); + +void block_signals(sigset_t *); + +void set_signals(sigset_t *); + +int orangefs_unmount_sb(struct super_block *sb); + +int orangefs_cancel_op_in_progress(__u64 tag); + +static inline __u64 orangefs_convert_time_field(const struct timespec *ts) +{ + return (__u64)ts->tv_sec; +} + +int orangefs_normalize_to_errno(__s32 error_code); + +extern struct mutex devreq_mutex; +extern struct mutex request_mutex; +extern int debug; +extern int op_timeout_secs; +extern int slot_timeout_secs; +extern struct list_head orangefs_superblocks; +extern spinlock_t orangefs_superblocks_lock; +extern struct list_head orangefs_request_list; +extern spinlock_t orangefs_request_list_lock; +extern wait_queue_head_t orangefs_request_list_waitq; +extern struct list_head *htable_ops_in_progress; +extern spinlock_t htable_ops_in_progress_lock; +extern int hash_table_size; + +extern const struct address_space_operations orangefs_address_operations; +extern struct backing_dev_info orangefs_backing_dev_info; +extern struct inode_operations orangefs_file_inode_operations; +extern const struct file_operations orangefs_file_operations; +extern struct inode_operations orangefs_symlink_inode_operations; +extern struct inode_operations orangefs_dir_inode_operations; +extern const struct file_operations orangefs_dir_operations; +extern const struct dentry_operations orangefs_dentry_operations; +extern const struct file_operations orangefs_devreq_file_operations; + +extern wait_queue_head_t orangefs_bufmap_init_waitq; + +/* + * misc convenience macros + */ +#define add_op_to_request_list(op) \ +do { \ + spin_lock(&orangefs_request_list_lock); \ + spin_lock(&op->lock); \ + set_op_state_waiting(op); \ + list_add_tail(&op->list, &orangefs_request_list); \ + spin_unlock(&orangefs_request_list_lock); \ + spin_unlock(&op->lock); \ + wake_up_interruptible(&orangefs_request_list_waitq); \ +} while (0) + +#define add_priority_op_to_request_list(op) \ + do { \ + spin_lock(&orangefs_request_list_lock); \ + spin_lock(&op->lock); \ + set_op_state_waiting(op); \ + \ + list_add(&op->list, &orangefs_request_list); \ + spin_unlock(&orangefs_request_list_lock); \ + spin_unlock(&op->lock); \ + wake_up_interruptible(&orangefs_request_list_waitq); \ +} while (0) + +#define remove_op_from_request_list(op) \ + do { \ + struct list_head *tmp = NULL; \ + struct list_head *tmp_safe = NULL; \ + struct orangefs_kernel_op_s *tmp_op = NULL; \ + \ + spin_lock(&orangefs_request_list_lock); \ + list_for_each_safe(tmp, tmp_safe, &orangefs_request_list) { \ + tmp_op = list_entry(tmp, \ + struct orangefs_kernel_op_s, \ + list); \ + if (tmp_op && (tmp_op == op)) { \ + list_del(&tmp_op->list); \ + break; \ + } \ + } \ + spin_unlock(&orangefs_request_list_lock); \ + } while (0) + +#define ORANGEFS_OP_INTERRUPTIBLE 1 /* service_operation() is interruptible */ +#define ORANGEFS_OP_PRIORITY 2 /* service_operation() is high priority */ +#define ORANGEFS_OP_CANCELLATION 4 /* this is a cancellation */ +#define ORANGEFS_OP_NO_SEMAPHORE 8 /* don't acquire semaphore */ +#define ORANGEFS_OP_ASYNC 16 /* Queue it, but don't wait */ + +int service_operation(struct orangefs_kernel_op_s *op, + const char *op_name, + int flags); + +/* + * handles two possible error cases, depending on context. + * + * by design, our vfs i/o errors need to be handled in one of two ways, + * depending on where the error occured. + * + * if the error happens in the waitqueue code because we either timed + * out or a signal was raised while waiting, we need to cancel the + * userspace i/o operation and free the op manually. this is done to + * avoid having the device start writing application data to our shared + * bufmap pages without us expecting it. + * + * FIXME: POSSIBLE OPTIMIZATION: + * However, if we timed out or if we got a signal AND our upcall was never + * picked off the queue (i.e. we were in OP_VFS_STATE_WAITING), then we don't + * need to send a cancellation upcall. The way we can handle this is + * set error_exit to 2 in such cases and 1 whenever cancellation has to be + * sent and have handle_error + * take care of this situation as well.. + * + * if a orangefs sysint level error occured and i/o has been completed, + * there is no need to cancel the operation, as the user has finished + * using the bufmap page and so there is no danger in this case. in + * this case, we wake up the device normally so that it may free the + * op, as normal. + * + * note the only reason this is a macro is because both read and write + * cases need the exact same handling code. + */ +#define handle_io_error() \ +do { \ + if (!op_state_serviced(new_op)) { \ + orangefs_cancel_op_in_progress(new_op->tag); \ + op_release(new_op); \ + } else { \ + wake_up_daemon_for_return(new_op); \ + } \ + new_op = NULL; \ + orangefs_bufmap_put(bufmap, buffer_index); \ + buffer_index = -1; \ +} while (0) + +#define get_interruptible_flag(inode) \ + ((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \ + ORANGEFS_OP_INTERRUPTIBLE : 0) + +#define add_orangefs_sb(sb) \ +do { \ + gossip_debug(GOSSIP_SUPER_DEBUG, \ + "Adding SB %p to orangefs superblocks\n", \ + ORANGEFS_SB(sb)); \ + spin_lock(&orangefs_superblocks_lock); \ + list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); \ + spin_unlock(&orangefs_superblocks_lock); \ +} while (0) + +#define remove_orangefs_sb(sb) \ +do { \ + struct list_head *tmp = NULL; \ + struct list_head *tmp_safe = NULL; \ + struct orangefs_sb_info_s *orangefs_sb = NULL; \ + \ + spin_lock(&orangefs_superblocks_lock); \ + list_for_each_safe(tmp, tmp_safe, &orangefs_superblocks) { \ + orangefs_sb = list_entry(tmp, \ + struct orangefs_sb_info_s, \ + list); \ + if (orangefs_sb && (orangefs_sb->sb == sb)) { \ + gossip_debug(GOSSIP_SUPER_DEBUG, \ + "Removing SB %p from orangefs superblocks\n", \ + orangefs_sb); \ + list_del(&orangefs_sb->list); \ + break; \ + } \ + } \ + spin_unlock(&orangefs_superblocks_lock); \ +} while (0) + +#define orangefs_lock_inode(inode) spin_lock(&inode->i_lock) +#define orangefs_unlock_inode(inode) spin_unlock(&inode->i_lock) + +#define fill_default_sys_attrs(sys_attr, type, mode) \ +do { \ + sys_attr.owner = from_kuid(current_user_ns(), current_fsuid()); \ + sys_attr.group = from_kgid(current_user_ns(), current_fsgid()); \ + sys_attr.size = 0; \ + sys_attr.perms = ORANGEFS_util_translate_mode(mode); \ + sys_attr.objtype = type; \ + sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE; \ +} while (0) + +#define orangefs_inode_lock(__i) mutex_lock(&(__i)->i_mutex) + +#define orangefs_inode_unlock(__i) mutex_unlock(&(__i)->i_mutex) + +static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size) +{ +#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) + ornagefs_inode_lock(inode); +#endif + i_size_write(inode, i_size); +#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) + orangefs_inode_unlock(inode); +#endif +} + +static inline unsigned int diff(struct timeval *end, struct timeval *begin) +{ + if (end->tv_usec < begin->tv_usec) { + end->tv_usec += 1000000; + end->tv_sec--; + } + end->tv_sec -= begin->tv_sec; + end->tv_usec -= begin->tv_usec; + return (end->tv_sec * 1000000) + end->tv_usec; +} + +#endif /* __ORANGEFSKERNEL_H */ diff --git a/fs/orangefs/orangefs-mod.c b/fs/orangefs/orangefs-mod.c new file mode 100644 index 000000000000..fa2fca6dca7c --- /dev/null +++ b/fs/orangefs/orangefs-mod.c @@ -0,0 +1,315 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * Changes by Acxiom Corporation to add proc file handler for pvfs2 client + * parameters, Copyright Acxiom Corporation, 2005. + * + * See COPYING in top-level directory. + */ + +#include "protocol.h" +#include "orangefs-kernel.h" +#include "orangefs-debugfs.h" +#include "orangefs-sysfs.h" + +/* ORANGEFS_VERSION is a ./configure define */ +#ifndef ORANGEFS_VERSION +#define ORANGEFS_VERSION "Unknown" +#endif + +/* + * global variables declared here + */ + +/* array of client debug keyword/mask values */ +struct client_debug_mask *cdm_array; +int cdm_element_count; + +char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN] = "none"; +char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; +char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; + +char *debug_help_string; +int help_string_initialized; +struct dentry *help_file_dentry; +struct dentry *client_debug_dentry; +struct dentry *debug_dir; +int client_verbose_index; +int client_all_index; +struct orangefs_stats g_orangefs_stats; + +/* the size of the hash tables for ops in progress */ +int hash_table_size = 509; + +static ulong module_parm_debug_mask; +__u64 gossip_debug_mask; +struct client_debug_mask client_debug_mask = { NULL, 0, 0 }; +unsigned int kernel_mask_set_mod_init; /* implicitly false */ +int op_timeout_secs = ORANGEFS_DEFAULT_OP_TIMEOUT_SECS; +int slot_timeout_secs = ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS; + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("ORANGEFS Development Team"); +MODULE_DESCRIPTION("The Linux Kernel VFS interface to ORANGEFS"); +MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see orangefs-debug.h for values)"); +MODULE_PARM_DESC(op_timeout_secs, "Operation timeout in seconds"); +MODULE_PARM_DESC(slot_timeout_secs, "Slot timeout in seconds"); +MODULE_PARM_DESC(hash_table_size, + "size of hash table for operations in progress"); + +static struct file_system_type orangefs_fs_type = { + .name = "pvfs2", + .mount = orangefs_mount, + .kill_sb = orangefs_kill_sb, + .owner = THIS_MODULE, +}; + +module_param(hash_table_size, int, 0); +module_param(module_parm_debug_mask, ulong, 0644); +module_param(op_timeout_secs, int, 0); +module_param(slot_timeout_secs, int, 0); + +/* synchronizes the request device file */ +struct mutex devreq_mutex; + +/* + * Blocks non-priority requests from being queued for servicing. This + * could be used for protecting the request list data structure, but + * for now it's only being used to stall the op addition to the request + * list + */ +struct mutex request_mutex; + +/* hash table for storing operations waiting for matching downcall */ +struct list_head *htable_ops_in_progress; +DEFINE_SPINLOCK(htable_ops_in_progress_lock); + +/* list for queueing upcall operations */ +LIST_HEAD(orangefs_request_list); + +/* used to protect the above orangefs_request_list */ +DEFINE_SPINLOCK(orangefs_request_list_lock); + +/* used for incoming request notification */ +DECLARE_WAIT_QUEUE_HEAD(orangefs_request_list_waitq); + +static int __init orangefs_init(void) +{ + int ret = -1; + __u32 i = 0; + + /* convert input debug mask to a 64-bit unsigned integer */ + gossip_debug_mask = (unsigned long long) module_parm_debug_mask; + + /* + * set the kernel's gossip debug string; invalid mask values will + * be ignored. + */ + debug_mask_to_string(&gossip_debug_mask, 0); + + /* remove any invalid values from the mask */ + debug_string_to_mask(kernel_debug_string, &gossip_debug_mask, 0); + + /* + * if the mask has a non-zero value, then indicate that the mask + * was set when the kernel module was loaded. The orangefs dev ioctl + * command will look at this boolean to determine if the kernel's + * debug mask should be overwritten when the client-core is started. + */ + if (gossip_debug_mask != 0) + kernel_mask_set_mod_init = true; + + /* print information message to the system log */ + pr_info("orangefs: orangefs_init called with debug mask: :%s: :%llx:\n", + kernel_debug_string, + (unsigned long long)gossip_debug_mask); + + ret = bdi_init(&orangefs_backing_dev_info); + + if (ret) + return ret; + + if (op_timeout_secs < 0) + op_timeout_secs = 0; + + if (slot_timeout_secs < 0) + slot_timeout_secs = 0; + + /* initialize global book keeping data structures */ + ret = op_cache_initialize(); + if (ret < 0) + goto err; + + ret = dev_req_cache_initialize(); + if (ret < 0) + goto cleanup_op; + + ret = orangefs_inode_cache_initialize(); + if (ret < 0) + goto cleanup_req; + + ret = kiocb_cache_initialize(); + if (ret < 0) + goto cleanup_inode; + + /* Initialize the orangefsdev subsystem. */ + ret = orangefs_dev_init(); + if (ret < 0) { + gossip_err("orangefs: could not initialize device subsystem %d!\n", + ret); + goto cleanup_kiocb; + } + + mutex_init(&devreq_mutex); + mutex_init(&request_mutex); + + htable_ops_in_progress = + kcalloc(hash_table_size, sizeof(struct list_head), GFP_KERNEL); + if (!htable_ops_in_progress) { + gossip_err("Failed to initialize op hashtable"); + ret = -ENOMEM; + goto cleanup_device; + } + + /* initialize a doubly linked at each hash table index */ + for (i = 0; i < hash_table_size; i++) + INIT_LIST_HEAD(&htable_ops_in_progress[i]); + + ret = fsid_key_table_initialize(); + if (ret < 0) + goto cleanup_progress_table; + + /* + * Build the contents of /sys/kernel/debug/orangefs/debug-help + * from the keywords in the kernel keyword/mask array. + * + * The keywords in the client keyword/mask array are + * unknown at boot time. + * + * orangefs_prepare_debugfs_help_string will be used again + * later to rebuild the debug-help file after the client starts + * and passes along the needed info. The argument signifies + * which time orangefs_prepare_debugfs_help_string is being + * called. + * + */ + ret = orangefs_prepare_debugfs_help_string(1); + if (ret) + goto out; + + orangefs_debugfs_init(); + orangefs_kernel_debug_init(); + orangefs_sysfs_init(); + + ret = register_filesystem(&orangefs_fs_type); + if (ret == 0) { + pr_info("orangefs: module version %s loaded\n", ORANGEFS_VERSION); + return 0; + } + + orangefs_debugfs_cleanup(); + orangefs_sysfs_exit(); + fsid_key_table_finalize(); + +cleanup_progress_table: + kfree(htable_ops_in_progress); + +cleanup_device: + orangefs_dev_cleanup(); + +cleanup_kiocb: + kiocb_cache_finalize(); + +cleanup_inode: + orangefs_inode_cache_finalize(); + +cleanup_req: + dev_req_cache_finalize(); + +cleanup_op: + op_cache_finalize(); + +err: + bdi_destroy(&orangefs_backing_dev_info); + +out: + return ret; +} + +static void __exit orangefs_exit(void) +{ + int i = 0; + struct orangefs_kernel_op_s *cur_op = NULL; + + gossip_debug(GOSSIP_INIT_DEBUG, "orangefs: orangefs_exit called\n"); + + unregister_filesystem(&orangefs_fs_type); + orangefs_debugfs_cleanup(); + orangefs_sysfs_exit(); + fsid_key_table_finalize(); + orangefs_dev_cleanup(); + /* clear out all pending upcall op requests */ + spin_lock(&orangefs_request_list_lock); + while (!list_empty(&orangefs_request_list)) { + cur_op = list_entry(orangefs_request_list.next, + struct orangefs_kernel_op_s, + list); + list_del(&cur_op->list); + gossip_debug(GOSSIP_INIT_DEBUG, + "Freeing unhandled upcall request type %d\n", + cur_op->upcall.type); + op_release(cur_op); + } + spin_unlock(&orangefs_request_list_lock); + + for (i = 0; i < hash_table_size; i++) + while (!list_empty(&htable_ops_in_progress[i])) { + cur_op = list_entry(htable_ops_in_progress[i].next, + struct orangefs_kernel_op_s, + list); + op_release(cur_op); + } + + kiocb_cache_finalize(); + orangefs_inode_cache_finalize(); + dev_req_cache_finalize(); + op_cache_finalize(); + + kfree(htable_ops_in_progress); + + bdi_destroy(&orangefs_backing_dev_info); + + pr_info("orangefs: module version %s unloaded\n", ORANGEFS_VERSION); +} + +/* + * What we do in this function is to walk the list of operations + * that are in progress in the hash table and mark them as purged as well. + */ +void purge_inprogress_ops(void) +{ + int i; + + for (i = 0; i < hash_table_size; i++) { + struct orangefs_kernel_op_s *op; + struct orangefs_kernel_op_s *next; + + list_for_each_entry_safe(op, + next, + &htable_ops_in_progress[i], + list) { + spin_lock(&op->lock); + gossip_debug(GOSSIP_INIT_DEBUG, + "pvfs2-client-core: purging in-progress op tag " + "%llu %s\n", + llu(op->tag), + get_opname_string(op)); + set_op_state_purged(op); + spin_unlock(&op->lock); + wake_up_interruptible(&op->waitq); + } + } +} + +module_init(orangefs_init); +module_exit(orangefs_exit); diff --git a/fs/orangefs/orangefs-sysfs.c b/fs/orangefs/orangefs-sysfs.c new file mode 100644 index 000000000000..3d360383ea22 --- /dev/null +++ b/fs/orangefs/orangefs-sysfs.c @@ -0,0 +1,1787 @@ +/* + * Documentation/ABI/stable/orangefs-sysfs: + * + * What: /sys/fs/orangefs/perf_counter_reset + * Date: June 2015 + * Contact: Mike Marshall + * Description: + * echo a 0 or a 1 into perf_counter_reset to + * reset all the counters in + * /sys/fs/orangefs/perf_counters + * except ones with PINT_PERF_PRESERVE set. + * + * + * What: /sys/fs/orangefs/perf_counters/... + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Counters and settings for various caches. + * Read only. + * + * + * What: /sys/fs/orangefs/perf_time_interval_secs + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Length of perf counter intervals in + * seconds. + * + * + * What: /sys/fs/orangefs/perf_history_size + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * The perf_counters cache statistics have N, or + * perf_history_size, samples. The default is + * one. + * + * Every perf_time_interval_secs the (first) + * samples are reset. + * + * If N is greater than one, the "current" set + * of samples is reset, and the samples from the + * other N-1 intervals remain available. + * + * + * What: /sys/fs/orangefs/op_timeout_secs + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Service operation timeout in seconds. + * + * + * What: /sys/fs/orangefs/slot_timeout_secs + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * "Slot" timeout in seconds. A "slot" + * is an indexed buffer in the shared + * memory segment used for communication + * between the kernel module and userspace. + * Slots are requested and waited for, + * the wait times out after slot_timeout_secs. + * + * + * What: /sys/fs/orangefs/acache/... + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Attribute cache configurable settings. + * + * + * What: /sys/fs/orangefs/ncache/... + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Name cache configurable settings. + * + * + * What: /sys/fs/orangefs/capcache/... + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Capability cache configurable settings. + * + * + * What: /sys/fs/orangefs/ccache/... + * Date: Jun 2015 + * Contact: Mike Marshall + * Description: + * Credential cache configurable settings. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "protocol.h" +#include "orangefs-kernel.h" +#include "orangefs-sysfs.h" + +#define ORANGEFS_KOBJ_ID "orangefs" +#define ACACHE_KOBJ_ID "acache" +#define CAPCACHE_KOBJ_ID "capcache" +#define CCACHE_KOBJ_ID "ccache" +#define NCACHE_KOBJ_ID "ncache" +#define PC_KOBJ_ID "pc" +#define STATS_KOBJ_ID "stats" + +struct orangefs_obj { + struct kobject kobj; + int op_timeout_secs; + int perf_counter_reset; + int perf_history_size; + int perf_time_interval_secs; + int slot_timeout_secs; +}; + +struct acache_orangefs_obj { + struct kobject kobj; + int hard_limit; + int reclaim_percentage; + int soft_limit; + int timeout_msecs; +}; + +struct capcache_orangefs_obj { + struct kobject kobj; + int hard_limit; + int reclaim_percentage; + int soft_limit; + int timeout_secs; +}; + +struct ccache_orangefs_obj { + struct kobject kobj; + int hard_limit; + int reclaim_percentage; + int soft_limit; + int timeout_secs; +}; + +struct ncache_orangefs_obj { + struct kobject kobj; + int hard_limit; + int reclaim_percentage; + int soft_limit; + int timeout_msecs; +}; + +struct pc_orangefs_obj { + struct kobject kobj; + char *acache; + char *capcache; + char *ncache; +}; + +struct stats_orangefs_obj { + struct kobject kobj; + int reads; + int writes; +}; + +struct orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct orangefs_obj *orangefs_obj, + struct orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct orangefs_obj *orangefs_obj, + struct orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +struct acache_orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct acache_orangefs_obj *acache_orangefs_obj, + struct acache_orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct acache_orangefs_obj *acache_orangefs_obj, + struct acache_orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +struct capcache_orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct capcache_orangefs_obj *capcache_orangefs_obj, + struct capcache_orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct capcache_orangefs_obj *capcache_orangefs_obj, + struct capcache_orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +struct ccache_orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct ccache_orangefs_obj *ccache_orangefs_obj, + struct ccache_orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct ccache_orangefs_obj *ccache_orangefs_obj, + struct ccache_orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +struct ncache_orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct ncache_orangefs_obj *ncache_orangefs_obj, + struct ncache_orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct ncache_orangefs_obj *ncache_orangefs_obj, + struct ncache_orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +struct pc_orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct pc_orangefs_obj *pc_orangefs_obj, + struct pc_orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct pc_orangefs_obj *pc_orangefs_obj, + struct pc_orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +struct stats_orangefs_attribute { + struct attribute attr; + ssize_t (*show)(struct stats_orangefs_obj *stats_orangefs_obj, + struct stats_orangefs_attribute *attr, + char *buf); + ssize_t (*store)(struct stats_orangefs_obj *stats_orangefs_obj, + struct stats_orangefs_attribute *attr, + const char *buf, + size_t count); +}; + +static ssize_t orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct orangefs_attribute *attribute; + struct orangefs_obj *orangefs_obj; + int rc; + + attribute = container_of(attr, struct orangefs_attribute, attr); + orangefs_obj = container_of(kobj, struct orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(orangefs_obj, attribute, buf); + +out: + return rc; +} + +static ssize_t orangefs_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct orangefs_attribute *attribute; + struct orangefs_obj *orangefs_obj; + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "orangefs_attr_store: start\n"); + + attribute = container_of(attr, struct orangefs_attribute, attr); + orangefs_obj = container_of(kobj, struct orangefs_obj, kobj); + + if (!attribute->store) { + rc = -EIO; + goto out; + } + + rc = attribute->store(orangefs_obj, attribute, buf, len); + +out: + return rc; +} + +static const struct sysfs_ops orangefs_sysfs_ops = { + .show = orangefs_attr_show, + .store = orangefs_attr_store, +}; + +static ssize_t acache_orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct acache_orangefs_attribute *attribute; + struct acache_orangefs_obj *acache_orangefs_obj; + int rc; + + attribute = container_of(attr, struct acache_orangefs_attribute, attr); + acache_orangefs_obj = + container_of(kobj, struct acache_orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(acache_orangefs_obj, attribute, buf); + +out: + return rc; +} + +static ssize_t acache_orangefs_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct acache_orangefs_attribute *attribute; + struct acache_orangefs_obj *acache_orangefs_obj; + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "acache_orangefs_attr_store: start\n"); + + attribute = container_of(attr, struct acache_orangefs_attribute, attr); + acache_orangefs_obj = + container_of(kobj, struct acache_orangefs_obj, kobj); + + if (!attribute->store) { + rc = -EIO; + goto out; + } + + rc = attribute->store(acache_orangefs_obj, attribute, buf, len); + +out: + return rc; +} + +static const struct sysfs_ops acache_orangefs_sysfs_ops = { + .show = acache_orangefs_attr_show, + .store = acache_orangefs_attr_store, +}; + +static ssize_t capcache_orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct capcache_orangefs_attribute *attribute; + struct capcache_orangefs_obj *capcache_orangefs_obj; + int rc; + + attribute = + container_of(attr, struct capcache_orangefs_attribute, attr); + capcache_orangefs_obj = + container_of(kobj, struct capcache_orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(capcache_orangefs_obj, attribute, buf); + +out: + return rc; +} + +static ssize_t capcache_orangefs_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct capcache_orangefs_attribute *attribute; + struct capcache_orangefs_obj *capcache_orangefs_obj; + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "capcache_orangefs_attr_store: start\n"); + + attribute = + container_of(attr, struct capcache_orangefs_attribute, attr); + capcache_orangefs_obj = + container_of(kobj, struct capcache_orangefs_obj, kobj); + + if (!attribute->store) { + rc = -EIO; + goto out; + } + + rc = attribute->store(capcache_orangefs_obj, attribute, buf, len); + +out: + return rc; +} + +static const struct sysfs_ops capcache_orangefs_sysfs_ops = { + .show = capcache_orangefs_attr_show, + .store = capcache_orangefs_attr_store, +}; + +static ssize_t ccache_orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct ccache_orangefs_attribute *attribute; + struct ccache_orangefs_obj *ccache_orangefs_obj; + int rc; + + attribute = + container_of(attr, struct ccache_orangefs_attribute, attr); + ccache_orangefs_obj = + container_of(kobj, struct ccache_orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(ccache_orangefs_obj, attribute, buf); + +out: + return rc; +} + +static ssize_t ccache_orangefs_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct ccache_orangefs_attribute *attribute; + struct ccache_orangefs_obj *ccache_orangefs_obj; + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "ccache_orangefs_attr_store: start\n"); + + attribute = + container_of(attr, struct ccache_orangefs_attribute, attr); + ccache_orangefs_obj = + container_of(kobj, struct ccache_orangefs_obj, kobj); + + if (!attribute->store) { + rc = -EIO; + goto out; + } + + rc = attribute->store(ccache_orangefs_obj, attribute, buf, len); + +out: + return rc; +} + +static const struct sysfs_ops ccache_orangefs_sysfs_ops = { + .show = ccache_orangefs_attr_show, + .store = ccache_orangefs_attr_store, +}; + +static ssize_t ncache_orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct ncache_orangefs_attribute *attribute; + struct ncache_orangefs_obj *ncache_orangefs_obj; + int rc; + + attribute = container_of(attr, struct ncache_orangefs_attribute, attr); + ncache_orangefs_obj = + container_of(kobj, struct ncache_orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(ncache_orangefs_obj, attribute, buf); + +out: + return rc; +} + +static ssize_t ncache_orangefs_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct ncache_orangefs_attribute *attribute; + struct ncache_orangefs_obj *ncache_orangefs_obj; + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "ncache_orangefs_attr_store: start\n"); + + attribute = container_of(attr, struct ncache_orangefs_attribute, attr); + ncache_orangefs_obj = + container_of(kobj, struct ncache_orangefs_obj, kobj); + + if (!attribute->store) { + rc = -EIO; + goto out; + } + + rc = attribute->store(ncache_orangefs_obj, attribute, buf, len); + +out: + return rc; +} + +static const struct sysfs_ops ncache_orangefs_sysfs_ops = { + .show = ncache_orangefs_attr_show, + .store = ncache_orangefs_attr_store, +}; + +static ssize_t pc_orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct pc_orangefs_attribute *attribute; + struct pc_orangefs_obj *pc_orangefs_obj; + int rc; + + attribute = container_of(attr, struct pc_orangefs_attribute, attr); + pc_orangefs_obj = + container_of(kobj, struct pc_orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(pc_orangefs_obj, attribute, buf); + +out: + return rc; +} + +static const struct sysfs_ops pc_orangefs_sysfs_ops = { + .show = pc_orangefs_attr_show, +}; + +static ssize_t stats_orangefs_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct stats_orangefs_attribute *attribute; + struct stats_orangefs_obj *stats_orangefs_obj; + int rc; + + attribute = container_of(attr, struct stats_orangefs_attribute, attr); + stats_orangefs_obj = + container_of(kobj, struct stats_orangefs_obj, kobj); + + if (!attribute->show) { + rc = -EIO; + goto out; + } + + rc = attribute->show(stats_orangefs_obj, attribute, buf); + +out: + return rc; +} + +static const struct sysfs_ops stats_orangefs_sysfs_ops = { + .show = stats_orangefs_attr_show, +}; + +static void orangefs_release(struct kobject *kobj) +{ + struct orangefs_obj *orangefs_obj; + + orangefs_obj = container_of(kobj, struct orangefs_obj, kobj); + kfree(orangefs_obj); +} + +static void acache_orangefs_release(struct kobject *kobj) +{ + struct acache_orangefs_obj *acache_orangefs_obj; + + acache_orangefs_obj = + container_of(kobj, struct acache_orangefs_obj, kobj); + kfree(acache_orangefs_obj); +} + +static void capcache_orangefs_release(struct kobject *kobj) +{ + struct capcache_orangefs_obj *capcache_orangefs_obj; + + capcache_orangefs_obj = + container_of(kobj, struct capcache_orangefs_obj, kobj); + kfree(capcache_orangefs_obj); +} + +static void ccache_orangefs_release(struct kobject *kobj) +{ + struct ccache_orangefs_obj *ccache_orangefs_obj; + + ccache_orangefs_obj = + container_of(kobj, struct ccache_orangefs_obj, kobj); + kfree(ccache_orangefs_obj); +} + +static void ncache_orangefs_release(struct kobject *kobj) +{ + struct ncache_orangefs_obj *ncache_orangefs_obj; + + ncache_orangefs_obj = + container_of(kobj, struct ncache_orangefs_obj, kobj); + kfree(ncache_orangefs_obj); +} + +static void pc_orangefs_release(struct kobject *kobj) +{ + struct pc_orangefs_obj *pc_orangefs_obj; + + pc_orangefs_obj = + container_of(kobj, struct pc_orangefs_obj, kobj); + kfree(pc_orangefs_obj); +} + +static void stats_orangefs_release(struct kobject *kobj) +{ + struct stats_orangefs_obj *stats_orangefs_obj; + + stats_orangefs_obj = + container_of(kobj, struct stats_orangefs_obj, kobj); + kfree(stats_orangefs_obj); +} + +static ssize_t sysfs_int_show(char *kobj_id, char *buf, void *attr) +{ + int rc = -EIO; + struct orangefs_attribute *orangefs_attr; + struct stats_orangefs_attribute *stats_orangefs_attr; + + gossip_debug(GOSSIP_SYSFS_DEBUG, "sysfs_int_show: id:%s:\n", kobj_id); + + if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { + orangefs_attr = (struct orangefs_attribute *)attr; + + if (!strcmp(orangefs_attr->attr.name, "op_timeout_secs")) { + rc = scnprintf(buf, + PAGE_SIZE, + "%d\n", + op_timeout_secs); + goto out; + } else if (!strcmp(orangefs_attr->attr.name, + "slot_timeout_secs")) { + rc = scnprintf(buf, + PAGE_SIZE, + "%d\n", + slot_timeout_secs); + goto out; + } else { + goto out; + } + + } else if (!strcmp(kobj_id, STATS_KOBJ_ID)) { + stats_orangefs_attr = (struct stats_orangefs_attribute *)attr; + + if (!strcmp(stats_orangefs_attr->attr.name, "reads")) { + rc = scnprintf(buf, + PAGE_SIZE, + "%lu\n", + g_orangefs_stats.reads); + goto out; + } else if (!strcmp(stats_orangefs_attr->attr.name, "writes")) { + rc = scnprintf(buf, + PAGE_SIZE, + "%lu\n", + g_orangefs_stats.writes); + goto out; + } else { + goto out; + } + } + +out: + + return rc; +} + +static ssize_t int_orangefs_show(struct orangefs_obj *orangefs_obj, + struct orangefs_attribute *attr, + char *buf) +{ + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "int_orangefs_show:start attr->attr.name:%s:\n", + attr->attr.name); + + rc = sysfs_int_show(ORANGEFS_KOBJ_ID, buf, (void *) attr); + + return rc; +} + +static ssize_t int_stats_show(struct stats_orangefs_obj *stats_orangefs_obj, + struct stats_orangefs_attribute *attr, + char *buf) +{ + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "int_stats_show:start attr->attr.name:%s:\n", + attr->attr.name); + + rc = sysfs_int_show(STATS_KOBJ_ID, buf, (void *) attr); + + return rc; +} + +static ssize_t int_store(struct orangefs_obj *orangefs_obj, + struct orangefs_attribute *attr, + const char *buf, + size_t count) +{ + int rc = 0; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "int_store: start attr->attr.name:%s: buf:%s:\n", + attr->attr.name, buf); + + if (!strcmp(attr->attr.name, "op_timeout_secs")) { + rc = kstrtoint(buf, 0, &op_timeout_secs); + goto out; + } else if (!strcmp(attr->attr.name, "slot_timeout_secs")) { + rc = kstrtoint(buf, 0, &slot_timeout_secs); + goto out; + } else { + goto out; + } + +out: + if (rc) + rc = -EINVAL; + else + rc = count; + + return rc; +} + +/* + * obtain attribute values from userspace with a service operation. + */ +static int sysfs_service_op_show(char *kobj_id, char *buf, void *attr) +{ + struct orangefs_kernel_op_s *new_op = NULL; + int rc = 0; + char *ser_op_type = NULL; + struct orangefs_attribute *orangefs_attr; + struct acache_orangefs_attribute *acache_attr; + struct capcache_orangefs_attribute *capcache_attr; + struct ccache_orangefs_attribute *ccache_attr; + struct ncache_orangefs_attribute *ncache_attr; + struct pc_orangefs_attribute *pc_attr; + __u32 op_alloc_type; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "sysfs_service_op_show: id:%s:\n", + kobj_id); + + if (strcmp(kobj_id, PC_KOBJ_ID)) + op_alloc_type = ORANGEFS_VFS_OP_PARAM; + else + op_alloc_type = ORANGEFS_VFS_OP_PERF_COUNT; + + new_op = op_alloc(op_alloc_type); + if (!new_op) { + rc = -ENOMEM; + goto out; + } + + /* Can't do a service_operation if the client is not running... */ + rc = is_daemon_in_service(); + if (rc) { + pr_info("%s: Client not running :%d:\n", + __func__, + is_daemon_in_service()); + goto out; + } + + if (strcmp(kobj_id, PC_KOBJ_ID)) + new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_GET; + + if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { + orangefs_attr = (struct orangefs_attribute *)attr; + + if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE; + else if (!strcmp(orangefs_attr->attr.name, + "perf_time_interval_secs")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS; + else if (!strcmp(orangefs_attr->attr.name, + "perf_counter_reset")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_PERF_RESET; + + } else if (!strcmp(kobj_id, ACACHE_KOBJ_ID)) { + acache_attr = (struct acache_orangefs_attribute *)attr; + + if (!strcmp(acache_attr->attr.name, "timeout_msecs")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS; + + if (!strcmp(acache_attr->attr.name, "hard_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT; + + if (!strcmp(acache_attr->attr.name, "soft_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT; + + if (!strcmp(acache_attr->attr.name, "reclaim_percentage")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE; + + } else if (!strcmp(kobj_id, CAPCACHE_KOBJ_ID)) { + capcache_attr = (struct capcache_orangefs_attribute *)attr; + + if (!strcmp(capcache_attr->attr.name, "timeout_secs")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS; + + if (!strcmp(capcache_attr->attr.name, "hard_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT; + + if (!strcmp(capcache_attr->attr.name, "soft_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT; + + if (!strcmp(capcache_attr->attr.name, "reclaim_percentage")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE; + + } else if (!strcmp(kobj_id, CCACHE_KOBJ_ID)) { + ccache_attr = (struct ccache_orangefs_attribute *)attr; + + if (!strcmp(ccache_attr->attr.name, "timeout_secs")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS; + + if (!strcmp(ccache_attr->attr.name, "hard_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT; + + if (!strcmp(ccache_attr->attr.name, "soft_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT; + + if (!strcmp(ccache_attr->attr.name, "reclaim_percentage")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE; + + } else if (!strcmp(kobj_id, NCACHE_KOBJ_ID)) { + ncache_attr = (struct ncache_orangefs_attribute *)attr; + + if (!strcmp(ncache_attr->attr.name, "timeout_msecs")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS; + + if (!strcmp(ncache_attr->attr.name, "hard_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT; + + if (!strcmp(ncache_attr->attr.name, "soft_limit")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT; + + if (!strcmp(ncache_attr->attr.name, "reclaim_percentage")) + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE; + + } else if (!strcmp(kobj_id, PC_KOBJ_ID)) { + pc_attr = (struct pc_orangefs_attribute *)attr; + + if (!strcmp(pc_attr->attr.name, ACACHE_KOBJ_ID)) + new_op->upcall.req.perf_count.type = + ORANGEFS_PERF_COUNT_REQUEST_ACACHE; + + if (!strcmp(pc_attr->attr.name, CAPCACHE_KOBJ_ID)) + new_op->upcall.req.perf_count.type = + ORANGEFS_PERF_COUNT_REQUEST_CAPCACHE; + + if (!strcmp(pc_attr->attr.name, NCACHE_KOBJ_ID)) + new_op->upcall.req.perf_count.type = + ORANGEFS_PERF_COUNT_REQUEST_NCACHE; + + } else { + gossip_err("sysfs_service_op_show: unknown kobj_id:%s:\n", + kobj_id); + rc = -EINVAL; + goto out; + } + + + if (strcmp(kobj_id, PC_KOBJ_ID)) + ser_op_type = "orangefs_param"; + else + ser_op_type = "orangefs_perf_count"; + + /* + * The service_operation will return an errno return code on + * error, and zero on success. + */ + rc = service_operation(new_op, ser_op_type, ORANGEFS_OP_INTERRUPTIBLE); + +out: + if (!rc) { + if (strcmp(kobj_id, PC_KOBJ_ID)) { + rc = scnprintf(buf, + PAGE_SIZE, + "%d\n", + (int)new_op->downcall.resp.param.value); + } else { + rc = scnprintf( + buf, + PAGE_SIZE, + "%s", + new_op->downcall.resp.perf_count.buffer); + } + } + + /* + * if we got ENOMEM, then op_alloc probably failed... + */ + if (rc != -ENOMEM) + op_release(new_op); + + return rc; + +} + +static ssize_t service_orangefs_show(struct orangefs_obj *orangefs_obj, + struct orangefs_attribute *attr, + char *buf) +{ + int rc = 0; + + rc = sysfs_service_op_show(ORANGEFS_KOBJ_ID, buf, (void *)attr); + + return rc; +} + +static ssize_t + service_acache_show(struct acache_orangefs_obj *acache_orangefs_obj, + struct acache_orangefs_attribute *attr, + char *buf) +{ + int rc = 0; + + rc = sysfs_service_op_show(ACACHE_KOBJ_ID, buf, (void *)attr); + + return rc; +} + +static ssize_t service_capcache_show(struct capcache_orangefs_obj + *capcache_orangefs_obj, + struct capcache_orangefs_attribute *attr, + char *buf) +{ + int rc = 0; + + rc = sysfs_service_op_show(CAPCACHE_KOBJ_ID, buf, (void *)attr); + + return rc; +} + +static ssize_t service_ccache_show(struct ccache_orangefs_obj + *ccache_orangefs_obj, + struct ccache_orangefs_attribute *attr, + char *buf) +{ + int rc = 0; + + rc = sysfs_service_op_show(CCACHE_KOBJ_ID, buf, (void *)attr); + + return rc; +} + +static ssize_t + service_ncache_show(struct ncache_orangefs_obj *ncache_orangefs_obj, + struct ncache_orangefs_attribute *attr, + char *buf) +{ + int rc = 0; + + rc = sysfs_service_op_show(NCACHE_KOBJ_ID, buf, (void *)attr); + + return rc; +} + +static ssize_t + service_pc_show(struct pc_orangefs_obj *pc_orangefs_obj, + struct pc_orangefs_attribute *attr, + char *buf) +{ + int rc = 0; + + rc = sysfs_service_op_show(PC_KOBJ_ID, buf, (void *)attr); + + return rc; +} + +/* + * pass attribute values back to userspace with a service operation. + * + * We have to do a memory allocation, an sscanf and a service operation. + * And we have to evaluate what the user entered, to make sure the + * value is within the range supported by the attribute. So, there's + * a lot of return code checking and mapping going on here. + * + * We want to return 1 if we think everything went OK, and + * EINVAL if not. + */ +static int sysfs_service_op_store(char *kobj_id, const char *buf, void *attr) +{ + struct orangefs_kernel_op_s *new_op = NULL; + int val = 0; + int rc = 0; + struct orangefs_attribute *orangefs_attr; + struct acache_orangefs_attribute *acache_attr; + struct capcache_orangefs_attribute *capcache_attr; + struct ccache_orangefs_attribute *ccache_attr; + struct ncache_orangefs_attribute *ncache_attr; + + gossip_debug(GOSSIP_SYSFS_DEBUG, + "sysfs_service_op_store: id:%s:\n", + kobj_id); + + new_op = op_alloc(ORANGEFS_VFS_OP_PARAM); + if (!new_op) { + rc = -ENOMEM; + goto out; + } + + /* Can't do a service_operation if the client is not running... */ + rc = is_daemon_in_service(); + if (rc) { + pr_info("%s: Client not running :%d:\n", + __func__, + is_daemon_in_service()); + goto out; + } + + /* + * The value we want to send back to userspace is in buf. + */ + rc = kstrtoint(buf, 0, &val); + if (rc) + goto out; + + if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { + orangefs_attr = (struct orangefs_attribute *)attr; + + if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) { + if (val > 0) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(orangefs_attr->attr.name, + "perf_time_interval_secs")) { + if (val > 0) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(orangefs_attr->attr.name, + "perf_counter_reset")) { + if ((val == 0) || (val == 1)) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_PERF_RESET; + } else { + rc = 0; + goto out; + } + } + + } else if (!strcmp(kobj_id, ACACHE_KOBJ_ID)) { + acache_attr = (struct acache_orangefs_attribute *)attr; + + if (!strcmp(acache_attr->attr.name, "hard_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(acache_attr->attr.name, "soft_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(acache_attr->attr.name, + "reclaim_percentage")) { + if ((val > -1) && (val < 101)) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(acache_attr->attr.name, "timeout_msecs")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS; + } else { + rc = 0; + goto out; + } + } + + } else if (!strcmp(kobj_id, CAPCACHE_KOBJ_ID)) { + capcache_attr = (struct capcache_orangefs_attribute *)attr; + + if (!strcmp(capcache_attr->attr.name, "hard_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(capcache_attr->attr.name, "soft_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(capcache_attr->attr.name, + "reclaim_percentage")) { + if ((val > -1) && (val < 101)) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(capcache_attr->attr.name, "timeout_secs")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS; + } else { + rc = 0; + goto out; + } + } + + } else if (!strcmp(kobj_id, CCACHE_KOBJ_ID)) { + ccache_attr = (struct ccache_orangefs_attribute *)attr; + + if (!strcmp(ccache_attr->attr.name, "hard_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(ccache_attr->attr.name, "soft_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(ccache_attr->attr.name, + "reclaim_percentage")) { + if ((val > -1) && (val < 101)) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(ccache_attr->attr.name, "timeout_secs")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS; + } else { + rc = 0; + goto out; + } + } + + } else if (!strcmp(kobj_id, NCACHE_KOBJ_ID)) { + ncache_attr = (struct ncache_orangefs_attribute *)attr; + + if (!strcmp(ncache_attr->attr.name, "hard_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(ncache_attr->attr.name, "soft_limit")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(ncache_attr->attr.name, + "reclaim_percentage")) { + if ((val > -1) && (val < 101)) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE; + } else { + rc = 0; + goto out; + } + } else if (!strcmp(ncache_attr->attr.name, "timeout_msecs")) { + if (val > -1) { + new_op->upcall.req.param.op = + ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS; + } else { + rc = 0; + goto out; + } + } + + } else { + gossip_err("sysfs_service_op_store: unknown kobj_id:%s:\n", + kobj_id); + rc = -EINVAL; + goto out; + } + + new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET; + + new_op->upcall.req.param.value = val; + + /* + * The service_operation will return a errno return code on + * error, and zero on success. + */ + rc = service_operation(new_op, "orangefs_param", ORANGEFS_OP_INTERRUPTIBLE); + + if (rc < 0) { + gossip_err("sysfs_service_op_store: service op returned:%d:\n", + rc); + rc = 0; + } else { + rc = 1; + } + +out: + /* + * if we got ENOMEM, then op_alloc probably failed... + */ + if (rc == -ENOMEM) + rc = 0; + else + op_release(new_op); + + if (rc == 0) + rc = -EINVAL; + + return rc; +} + +static ssize_t + service_orangefs_store(struct orangefs_obj *orangefs_obj, + struct orangefs_attribute *attr, + const char *buf, + size_t count) +{ + int rc = 0; + + rc = sysfs_service_op_store(ORANGEFS_KOBJ_ID, buf, (void *) attr); + + /* rc should have an errno value if the service_op went bad. */ + if (rc == 1) + rc = count; + + return rc; +} + +static ssize_t + service_acache_store(struct acache_orangefs_obj *acache_orangefs_obj, + struct acache_orangefs_attribute *attr, + const char *buf, + size_t count) +{ + int rc = 0; + + rc = sysfs_service_op_store(ACACHE_KOBJ_ID, buf, (void *) attr); + + /* rc should have an errno value if the service_op went bad. */ + if (rc == 1) + rc = count; + + return rc; +} + +static ssize_t + service_capcache_store(struct capcache_orangefs_obj + *capcache_orangefs_obj, + struct capcache_orangefs_attribute *attr, + const char *buf, + size_t count) +{ + int rc = 0; + + rc = sysfs_service_op_store(CAPCACHE_KOBJ_ID, buf, (void *) attr); + + /* rc should have an errno value if the service_op went bad. */ + if (rc == 1) + rc = count; + + return rc; +} + +static ssize_t service_ccache_store(struct ccache_orangefs_obj + *ccache_orangefs_obj, + struct ccache_orangefs_attribute *attr, + const char *buf, + size_t count) +{ + int rc = 0; + + rc = sysfs_service_op_store(CCACHE_KOBJ_ID, buf, (void *) attr); + + /* rc should have an errno value if the service_op went bad. */ + if (rc == 1) + rc = count; + + return rc; +} + +static ssize_t + service_ncache_store(struct ncache_orangefs_obj *ncache_orangefs_obj, + struct ncache_orangefs_attribute *attr, + const char *buf, + size_t count) +{ + int rc = 0; + + rc = sysfs_service_op_store(NCACHE_KOBJ_ID, buf, (void *) attr); + + /* rc should have an errno value if the service_op went bad. */ + if (rc == 1) + rc = count; + + return rc; +} + +static struct orangefs_attribute op_timeout_secs_attribute = + __ATTR(op_timeout_secs, 0664, int_orangefs_show, int_store); + +static struct orangefs_attribute slot_timeout_secs_attribute = + __ATTR(slot_timeout_secs, 0664, int_orangefs_show, int_store); + +static struct orangefs_attribute perf_counter_reset_attribute = + __ATTR(perf_counter_reset, + 0664, + service_orangefs_show, + service_orangefs_store); + +static struct orangefs_attribute perf_history_size_attribute = + __ATTR(perf_history_size, + 0664, + service_orangefs_show, + service_orangefs_store); + +static struct orangefs_attribute perf_time_interval_secs_attribute = + __ATTR(perf_time_interval_secs, + 0664, + service_orangefs_show, + service_orangefs_store); + +static struct attribute *orangefs_default_attrs[] = { + &op_timeout_secs_attribute.attr, + &slot_timeout_secs_attribute.attr, + &perf_counter_reset_attribute.attr, + &perf_history_size_attribute.attr, + &perf_time_interval_secs_attribute.attr, + NULL, +}; + +static struct kobj_type orangefs_ktype = { + .sysfs_ops = &orangefs_sysfs_ops, + .release = orangefs_release, + .default_attrs = orangefs_default_attrs, +}; + +static struct acache_orangefs_attribute acache_hard_limit_attribute = + __ATTR(hard_limit, + 0664, + service_acache_show, + service_acache_store); + +static struct acache_orangefs_attribute acache_reclaim_percent_attribute = + __ATTR(reclaim_percentage, + 0664, + service_acache_show, + service_acache_store); + +static struct acache_orangefs_attribute acache_soft_limit_attribute = + __ATTR(soft_limit, + 0664, + service_acache_show, + service_acache_store); + +static struct acache_orangefs_attribute acache_timeout_msecs_attribute = + __ATTR(timeout_msecs, + 0664, + service_acache_show, + service_acache_store); + +static struct attribute *acache_orangefs_default_attrs[] = { + &acache_hard_limit_attribute.attr, + &acache_reclaim_percent_attribute.attr, + &acache_soft_limit_attribute.attr, + &acache_timeout_msecs_attribute.attr, + NULL, +}; + +static struct kobj_type acache_orangefs_ktype = { + .sysfs_ops = &acache_orangefs_sysfs_ops, + .release = acache_orangefs_release, + .default_attrs = acache_orangefs_default_attrs, +}; + +static struct capcache_orangefs_attribute capcache_hard_limit_attribute = + __ATTR(hard_limit, + 0664, + service_capcache_show, + service_capcache_store); + +static struct capcache_orangefs_attribute capcache_reclaim_percent_attribute = + __ATTR(reclaim_percentage, + 0664, + service_capcache_show, + service_capcache_store); + +static struct capcache_orangefs_attribute capcache_soft_limit_attribute = + __ATTR(soft_limit, + 0664, + service_capcache_show, + service_capcache_store); + +static struct capcache_orangefs_attribute capcache_timeout_secs_attribute = + __ATTR(timeout_secs, + 0664, + service_capcache_show, + service_capcache_store); + +static struct attribute *capcache_orangefs_default_attrs[] = { + &capcache_hard_limit_attribute.attr, + &capcache_reclaim_percent_attribute.attr, + &capcache_soft_limit_attribute.attr, + &capcache_timeout_secs_attribute.attr, + NULL, +}; + +static struct kobj_type capcache_orangefs_ktype = { + .sysfs_ops = &capcache_orangefs_sysfs_ops, + .release = capcache_orangefs_release, + .default_attrs = capcache_orangefs_default_attrs, +}; + +static struct ccache_orangefs_attribute ccache_hard_limit_attribute = + __ATTR(hard_limit, + 0664, + service_ccache_show, + service_ccache_store); + +static struct ccache_orangefs_attribute ccache_reclaim_percent_attribute = + __ATTR(reclaim_percentage, + 0664, + service_ccache_show, + service_ccache_store); + +static struct ccache_orangefs_attribute ccache_soft_limit_attribute = + __ATTR(soft_limit, + 0664, + service_ccache_show, + service_ccache_store); + +static struct ccache_orangefs_attribute ccache_timeout_secs_attribute = + __ATTR(timeout_secs, + 0664, + service_ccache_show, + service_ccache_store); + +static struct attribute *ccache_orangefs_default_attrs[] = { + &ccache_hard_limit_attribute.attr, + &ccache_reclaim_percent_attribute.attr, + &ccache_soft_limit_attribute.attr, + &ccache_timeout_secs_attribute.attr, + NULL, +}; + +static struct kobj_type ccache_orangefs_ktype = { + .sysfs_ops = &ccache_orangefs_sysfs_ops, + .release = ccache_orangefs_release, + .default_attrs = ccache_orangefs_default_attrs, +}; + +static struct ncache_orangefs_attribute ncache_hard_limit_attribute = + __ATTR(hard_limit, + 0664, + service_ncache_show, + service_ncache_store); + +static struct ncache_orangefs_attribute ncache_reclaim_percent_attribute = + __ATTR(reclaim_percentage, + 0664, + service_ncache_show, + service_ncache_store); + +static struct ncache_orangefs_attribute ncache_soft_limit_attribute = + __ATTR(soft_limit, + 0664, + service_ncache_show, + service_ncache_store); + +static struct ncache_orangefs_attribute ncache_timeout_msecs_attribute = + __ATTR(timeout_msecs, + 0664, + service_ncache_show, + service_ncache_store); + +static struct attribute *ncache_orangefs_default_attrs[] = { + &ncache_hard_limit_attribute.attr, + &ncache_reclaim_percent_attribute.attr, + &ncache_soft_limit_attribute.attr, + &ncache_timeout_msecs_attribute.attr, + NULL, +}; + +static struct kobj_type ncache_orangefs_ktype = { + .sysfs_ops = &ncache_orangefs_sysfs_ops, + .release = ncache_orangefs_release, + .default_attrs = ncache_orangefs_default_attrs, +}; + +static struct pc_orangefs_attribute pc_acache_attribute = + __ATTR(acache, + 0664, + service_pc_show, + NULL); + +static struct pc_orangefs_attribute pc_capcache_attribute = + __ATTR(capcache, + 0664, + service_pc_show, + NULL); + +static struct pc_orangefs_attribute pc_ncache_attribute = + __ATTR(ncache, + 0664, + service_pc_show, + NULL); + +static struct attribute *pc_orangefs_default_attrs[] = { + &pc_acache_attribute.attr, + &pc_capcache_attribute.attr, + &pc_ncache_attribute.attr, + NULL, +}; + +static struct kobj_type pc_orangefs_ktype = { + .sysfs_ops = &pc_orangefs_sysfs_ops, + .release = pc_orangefs_release, + .default_attrs = pc_orangefs_default_attrs, +}; + +static struct stats_orangefs_attribute stats_reads_attribute = + __ATTR(reads, + 0664, + int_stats_show, + NULL); + +static struct stats_orangefs_attribute stats_writes_attribute = + __ATTR(writes, + 0664, + int_stats_show, + NULL); + +static struct attribute *stats_orangefs_default_attrs[] = { + &stats_reads_attribute.attr, + &stats_writes_attribute.attr, + NULL, +}; + +static struct kobj_type stats_orangefs_ktype = { + .sysfs_ops = &stats_orangefs_sysfs_ops, + .release = stats_orangefs_release, + .default_attrs = stats_orangefs_default_attrs, +}; + +static struct orangefs_obj *orangefs_obj; +static struct acache_orangefs_obj *acache_orangefs_obj; +static struct capcache_orangefs_obj *capcache_orangefs_obj; +static struct ccache_orangefs_obj *ccache_orangefs_obj; +static struct ncache_orangefs_obj *ncache_orangefs_obj; +static struct pc_orangefs_obj *pc_orangefs_obj; +static struct stats_orangefs_obj *stats_orangefs_obj; + +int orangefs_sysfs_init(void) +{ + int rc; + + gossip_debug(GOSSIP_SYSFS_DEBUG, "orangefs_sysfs_init: start\n"); + + /* create /sys/fs/orangefs. */ + orangefs_obj = kzalloc(sizeof(*orangefs_obj), GFP_KERNEL); + if (!orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&orangefs_obj->kobj, + &orangefs_ktype, + fs_kobj, + ORANGEFS_KOBJ_ID); + + if (rc) { + kobject_put(&orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&orangefs_obj->kobj, KOBJ_ADD); + + /* create /sys/fs/orangefs/acache. */ + acache_orangefs_obj = kzalloc(sizeof(*acache_orangefs_obj), GFP_KERNEL); + if (!acache_orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&acache_orangefs_obj->kobj, + &acache_orangefs_ktype, + &orangefs_obj->kobj, + ACACHE_KOBJ_ID); + + if (rc) { + kobject_put(&acache_orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&acache_orangefs_obj->kobj, KOBJ_ADD); + + /* create /sys/fs/orangefs/capcache. */ + capcache_orangefs_obj = + kzalloc(sizeof(*capcache_orangefs_obj), GFP_KERNEL); + if (!capcache_orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&capcache_orangefs_obj->kobj, + &capcache_orangefs_ktype, + &orangefs_obj->kobj, + CAPCACHE_KOBJ_ID); + if (rc) { + kobject_put(&capcache_orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&capcache_orangefs_obj->kobj, KOBJ_ADD); + + /* create /sys/fs/orangefs/ccache. */ + ccache_orangefs_obj = + kzalloc(sizeof(*ccache_orangefs_obj), GFP_KERNEL); + if (!ccache_orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&ccache_orangefs_obj->kobj, + &ccache_orangefs_ktype, + &orangefs_obj->kobj, + CCACHE_KOBJ_ID); + if (rc) { + kobject_put(&ccache_orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&ccache_orangefs_obj->kobj, KOBJ_ADD); + + /* create /sys/fs/orangefs/ncache. */ + ncache_orangefs_obj = kzalloc(sizeof(*ncache_orangefs_obj), GFP_KERNEL); + if (!ncache_orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&ncache_orangefs_obj->kobj, + &ncache_orangefs_ktype, + &orangefs_obj->kobj, + NCACHE_KOBJ_ID); + + if (rc) { + kobject_put(&ncache_orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&ncache_orangefs_obj->kobj, KOBJ_ADD); + + /* create /sys/fs/orangefs/perf_counters. */ + pc_orangefs_obj = kzalloc(sizeof(*pc_orangefs_obj), GFP_KERNEL); + if (!pc_orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&pc_orangefs_obj->kobj, + &pc_orangefs_ktype, + &orangefs_obj->kobj, + "perf_counters"); + + if (rc) { + kobject_put(&pc_orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&pc_orangefs_obj->kobj, KOBJ_ADD); + + /* create /sys/fs/orangefs/stats. */ + stats_orangefs_obj = kzalloc(sizeof(*stats_orangefs_obj), GFP_KERNEL); + if (!stats_orangefs_obj) { + rc = -EINVAL; + goto out; + } + + rc = kobject_init_and_add(&stats_orangefs_obj->kobj, + &stats_orangefs_ktype, + &orangefs_obj->kobj, + STATS_KOBJ_ID); + + if (rc) { + kobject_put(&stats_orangefs_obj->kobj); + rc = -EINVAL; + goto out; + } + + kobject_uevent(&stats_orangefs_obj->kobj, KOBJ_ADD); +out: + return rc; +} + +void orangefs_sysfs_exit(void) +{ + gossip_debug(GOSSIP_SYSFS_DEBUG, "orangefs_sysfs_exit: start\n"); + + kobject_put(&acache_orangefs_obj->kobj); + kobject_put(&capcache_orangefs_obj->kobj); + kobject_put(&ccache_orangefs_obj->kobj); + kobject_put(&ncache_orangefs_obj->kobj); + kobject_put(&pc_orangefs_obj->kobj); + kobject_put(&stats_orangefs_obj->kobj); + + kobject_put(&orangefs_obj->kobj); +} diff --git a/fs/orangefs/orangefs-sysfs.h b/fs/orangefs/orangefs-sysfs.h new file mode 100644 index 000000000000..f0b76382db02 --- /dev/null +++ b/fs/orangefs/orangefs-sysfs.h @@ -0,0 +1,2 @@ +extern int orangefs_sysfs_init(void); +extern void orangefs_sysfs_exit(void); diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c new file mode 100644 index 000000000000..fa2a46521b7a --- /dev/null +++ b/fs/orangefs/orangefs-utils.c @@ -0,0 +1,1156 @@ +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ +#include "protocol.h" +#include "orangefs-kernel.h" +#include "orangefs-dev-proto.h" +#include "orangefs-bufmap.h" + +__s32 fsid_of_op(struct orangefs_kernel_op_s *op) +{ + __s32 fsid = ORANGEFS_FS_ID_NULL; + + if (op) { + switch (op->upcall.type) { + case ORANGEFS_VFS_OP_FILE_IO: + fsid = op->upcall.req.io.refn.fs_id; + break; + case ORANGEFS_VFS_OP_LOOKUP: + fsid = op->upcall.req.lookup.parent_refn.fs_id; + break; + case ORANGEFS_VFS_OP_CREATE: + fsid = op->upcall.req.create.parent_refn.fs_id; + break; + case ORANGEFS_VFS_OP_GETATTR: + fsid = op->upcall.req.getattr.refn.fs_id; + break; + case ORANGEFS_VFS_OP_REMOVE: + fsid = op->upcall.req.remove.parent_refn.fs_id; + break; + case ORANGEFS_VFS_OP_MKDIR: + fsid = op->upcall.req.mkdir.parent_refn.fs_id; + break; + case ORANGEFS_VFS_OP_READDIR: + fsid = op->upcall.req.readdir.refn.fs_id; + break; + case ORANGEFS_VFS_OP_SETATTR: + fsid = op->upcall.req.setattr.refn.fs_id; + break; + case ORANGEFS_VFS_OP_SYMLINK: + fsid = op->upcall.req.sym.parent_refn.fs_id; + break; + case ORANGEFS_VFS_OP_RENAME: + fsid = op->upcall.req.rename.old_parent_refn.fs_id; + break; + case ORANGEFS_VFS_OP_STATFS: + fsid = op->upcall.req.statfs.fs_id; + break; + case ORANGEFS_VFS_OP_TRUNCATE: + fsid = op->upcall.req.truncate.refn.fs_id; + break; + case ORANGEFS_VFS_OP_MMAP_RA_FLUSH: + fsid = op->upcall.req.ra_cache_flush.refn.fs_id; + break; + case ORANGEFS_VFS_OP_FS_UMOUNT: + fsid = op->upcall.req.fs_umount.fs_id; + break; + case ORANGEFS_VFS_OP_GETXATTR: + fsid = op->upcall.req.getxattr.refn.fs_id; + break; + case ORANGEFS_VFS_OP_SETXATTR: + fsid = op->upcall.req.setxattr.refn.fs_id; + break; + case ORANGEFS_VFS_OP_LISTXATTR: + fsid = op->upcall.req.listxattr.refn.fs_id; + break; + case ORANGEFS_VFS_OP_REMOVEXATTR: + fsid = op->upcall.req.removexattr.refn.fs_id; + break; + case ORANGEFS_VFS_OP_FSYNC: + fsid = op->upcall.req.fsync.refn.fs_id; + break; + default: + break; + } + } + return fsid; +} + +static void orangefs_set_inode_flags(struct inode *inode, + struct ORANGEFS_sys_attr_s *attrs) +{ + if (attrs->flags & ORANGEFS_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + + if (attrs->flags & ORANGEFS_APPEND_FL) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + + if (attrs->flags & ORANGEFS_NOATIME_FL) + inode->i_flags |= S_NOATIME; + else + inode->i_flags &= ~S_NOATIME; + +} + +/* NOTE: symname is ignored unless the inode is a sym link */ +static int copy_attributes_to_inode(struct inode *inode, + struct ORANGEFS_sys_attr_s *attrs, + char *symname) +{ + int ret = -1; + int perm_mode = 0; + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); + loff_t inode_size = 0; + loff_t rounded_up_size = 0; + + + /* + * arbitrarily set the inode block size; FIXME: we need to + * resolve the difference between the reported inode blocksize + * and the PAGE_CACHE_SIZE, since our block count will always + * be wrong. + * + * For now, we're setting the block count to be the proper + * number assuming the block size is 512 bytes, and the size is + * rounded up to the nearest 4K. This is apparently required + * to get proper size reports from the 'du' shell utility. + * + * changing the inode->i_blkbits to something other than + * PAGE_CACHE_SHIFT breaks mmap/execution as we depend on that. + */ + gossip_debug(GOSSIP_UTILS_DEBUG, + "attrs->mask = %x (objtype = %s)\n", + attrs->mask, + attrs->objtype == ORANGEFS_TYPE_METAFILE ? "file" : + attrs->objtype == ORANGEFS_TYPE_DIRECTORY ? "directory" : + attrs->objtype == ORANGEFS_TYPE_SYMLINK ? "symlink" : + "invalid/unknown"); + + switch (attrs->objtype) { + case ORANGEFS_TYPE_METAFILE: + orangefs_set_inode_flags(inode, attrs); + if (attrs->mask & ORANGEFS_ATTR_SYS_SIZE) { + inode_size = (loff_t) attrs->size; + rounded_up_size = + (inode_size + (4096 - (inode_size % 4096))); + + orangefs_lock_inode(inode); + inode->i_bytes = inode_size; + inode->i_blocks = + (unsigned long)(rounded_up_size / 512); + orangefs_unlock_inode(inode); + + /* + * NOTE: make sure all the places we're called + * from have the inode->i_sem lock. We're fine + * in 99% of the cases since we're mostly + * called from a lookup. + */ + inode->i_size = inode_size; + } + break; + case ORANGEFS_TYPE_SYMLINK: + if (symname != NULL) { + inode->i_size = (loff_t) strlen(symname); + break; + } + /*FALLTHRU*/ + default: + inode->i_size = PAGE_CACHE_SIZE; + + orangefs_lock_inode(inode); + inode_set_bytes(inode, inode->i_size); + orangefs_unlock_inode(inode); + break; + } + + inode->i_uid = make_kuid(&init_user_ns, attrs->owner); + inode->i_gid = make_kgid(&init_user_ns, attrs->group); + inode->i_atime.tv_sec = (time_t) attrs->atime; + inode->i_mtime.tv_sec = (time_t) attrs->mtime; + inode->i_ctime.tv_sec = (time_t) attrs->ctime; + inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; + inode->i_ctime.tv_nsec = 0; + + if (attrs->perms & ORANGEFS_O_EXECUTE) + perm_mode |= S_IXOTH; + if (attrs->perms & ORANGEFS_O_WRITE) + perm_mode |= S_IWOTH; + if (attrs->perms & ORANGEFS_O_READ) + perm_mode |= S_IROTH; + + if (attrs->perms & ORANGEFS_G_EXECUTE) + perm_mode |= S_IXGRP; + if (attrs->perms & ORANGEFS_G_WRITE) + perm_mode |= S_IWGRP; + if (attrs->perms & ORANGEFS_G_READ) + perm_mode |= S_IRGRP; + + if (attrs->perms & ORANGEFS_U_EXECUTE) + perm_mode |= S_IXUSR; + if (attrs->perms & ORANGEFS_U_WRITE) + perm_mode |= S_IWUSR; + if (attrs->perms & ORANGEFS_U_READ) + perm_mode |= S_IRUSR; + + if (attrs->perms & ORANGEFS_G_SGID) + perm_mode |= S_ISGID; + if (attrs->perms & ORANGEFS_U_SUID) + perm_mode |= S_ISUID; + + inode->i_mode = perm_mode; + + if (is_root_handle(inode)) { + /* special case: mark the root inode as sticky */ + inode->i_mode |= S_ISVTX; + gossip_debug(GOSSIP_UTILS_DEBUG, + "Marking inode %pU as sticky\n", + get_khandle_from_ino(inode)); + } + + switch (attrs->objtype) { + case ORANGEFS_TYPE_METAFILE: + inode->i_mode |= S_IFREG; + ret = 0; + break; + case ORANGEFS_TYPE_DIRECTORY: + inode->i_mode |= S_IFDIR; + /* NOTE: we have no good way to keep nlink consistent + * for directories across clients; keep constant at 1. + * Why 1? If we go with 2, then find(1) gets confused + * and won't work properly withouth the -noleaf option + */ + set_nlink(inode, 1); + ret = 0; + break; + case ORANGEFS_TYPE_SYMLINK: + inode->i_mode |= S_IFLNK; + + /* copy link target to inode private data */ + if (orangefs_inode && symname) { + strncpy(orangefs_inode->link_target, + symname, + ORANGEFS_NAME_MAX); + gossip_debug(GOSSIP_UTILS_DEBUG, + "Copied attr link target %s\n", + orangefs_inode->link_target); + } + gossip_debug(GOSSIP_UTILS_DEBUG, + "symlink mode %o\n", + inode->i_mode); + ret = 0; + break; + default: + gossip_err("orangefs: copy_attributes_to_inode: got invalid attribute type %x\n", + attrs->objtype); + } + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs: copy_attributes_to_inode: setting i_mode to %o, i_size to %lu\n", + inode->i_mode, + (unsigned long)i_size_read(inode)); + + return ret; +} + +/* + * NOTE: in kernel land, we never use the sys_attr->link_target for + * anything, so don't bother copying it into the sys_attr object here. + */ +static inline int copy_attributes_from_inode(struct inode *inode, + struct ORANGEFS_sys_attr_s *attrs, + struct iattr *iattr) +{ + umode_t tmp_mode; + + if (!iattr || !inode || !attrs) { + gossip_err("NULL iattr (%p), inode (%p), attrs (%p) " + "in copy_attributes_from_inode!\n", + iattr, + inode, + attrs); + return -EINVAL; + } + /* + * We need to be careful to only copy the attributes out of the + * iattr object that we know are valid. + */ + attrs->mask = 0; + if (iattr->ia_valid & ATTR_UID) { + attrs->owner = from_kuid(current_user_ns(), iattr->ia_uid); + attrs->mask |= ORANGEFS_ATTR_SYS_UID; + gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner); + } + if (iattr->ia_valid & ATTR_GID) { + attrs->group = from_kgid(current_user_ns(), iattr->ia_gid); + attrs->mask |= ORANGEFS_ATTR_SYS_GID; + gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group); + } + + if (iattr->ia_valid & ATTR_ATIME) { + attrs->mask |= ORANGEFS_ATTR_SYS_ATIME; + if (iattr->ia_valid & ATTR_ATIME_SET) { + attrs->atime = + orangefs_convert_time_field(&iattr->ia_atime); + attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET; + } + } + if (iattr->ia_valid & ATTR_MTIME) { + attrs->mask |= ORANGEFS_ATTR_SYS_MTIME; + if (iattr->ia_valid & ATTR_MTIME_SET) { + attrs->mtime = + orangefs_convert_time_field(&iattr->ia_mtime); + attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET; + } + } + if (iattr->ia_valid & ATTR_CTIME) + attrs->mask |= ORANGEFS_ATTR_SYS_CTIME; + + /* + * ORANGEFS cannot set size with a setattr operation. Probably not likely + * to be requested through the VFS, but just in case, don't worry about + * ATTR_SIZE + */ + + if (iattr->ia_valid & ATTR_MODE) { + tmp_mode = iattr->ia_mode; + if (tmp_mode & (S_ISVTX)) { + if (is_root_handle(inode)) { + /* + * allow sticky bit to be set on root (since + * it shows up that way by default anyhow), + * but don't show it to the server + */ + tmp_mode -= S_ISVTX; + } else { + gossip_debug(GOSSIP_UTILS_DEBUG, + "User attempted to set sticky bit on non-root directory; returning EINVAL.\n"); + return -EINVAL; + } + } + + if (tmp_mode & (S_ISUID)) { + gossip_debug(GOSSIP_UTILS_DEBUG, + "Attempting to set setuid bit (not supported); returning EINVAL.\n"); + return -EINVAL; + } + + attrs->perms = ORANGEFS_util_translate_mode(tmp_mode); + attrs->mask |= ORANGEFS_ATTR_SYS_PERM; + } + + return 0; +} + +/* + * issues a orangefs getattr request and fills in the appropriate inode + * attributes if successful. returns 0 on success; -errno otherwise + */ +int orangefs_inode_getattr(struct inode *inode, __u32 getattr_mask) +{ + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); + struct orangefs_kernel_op_s *new_op; + int ret = -EINVAL; + + gossip_debug(GOSSIP_UTILS_DEBUG, + "%s: called on inode %pU\n", + __func__, + get_khandle_from_ino(inode)); + + new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR); + if (!new_op) + return -ENOMEM; + new_op->upcall.req.getattr.refn = orangefs_inode->refn; + new_op->upcall.req.getattr.mask = getattr_mask; + + ret = service_operation(new_op, __func__, + get_interruptible_flag(inode)); + if (ret != 0) + goto out; + + if (copy_attributes_to_inode(inode, + &new_op->downcall.resp.getattr.attributes, + new_op->downcall.resp.getattr.link_target)) { + gossip_err("%s: failed to copy attributes\n", __func__); + ret = -ENOENT; + goto out; + } + + /* + * Store blksize in orangefs specific part of inode structure; we are + * only going to use this to report to stat to make sure it doesn't + * perturb any inode related code paths. + */ + if (new_op->downcall.resp.getattr.attributes.objtype == + ORANGEFS_TYPE_METAFILE) { + orangefs_inode->blksize = + new_op->downcall.resp.getattr.attributes.blksize; + } else { + /* mimic behavior of generic_fillattr() for other types. */ + orangefs_inode->blksize = (1 << inode->i_blkbits); + + } + +out: + gossip_debug(GOSSIP_UTILS_DEBUG, + "Getattr on handle %pU, " + "fsid %d\n (inode ct = %d) returned %d\n", + &orangefs_inode->refn.khandle, + orangefs_inode->refn.fs_id, + (int)atomic_read(&inode->i_count), + ret); + + op_release(new_op); + return ret; +} + +/* + * issues a orangefs setattr request to make sure the new attribute values + * take effect if successful. returns 0 on success; -errno otherwise + */ +int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr) +{ + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); + struct orangefs_kernel_op_s *new_op; + int ret; + + new_op = op_alloc(ORANGEFS_VFS_OP_SETATTR); + if (!new_op) + return -ENOMEM; + + new_op->upcall.req.setattr.refn = orangefs_inode->refn; + ret = copy_attributes_from_inode(inode, + &new_op->upcall.req.setattr.attributes, + iattr); + if (ret < 0) { + op_release(new_op); + return ret; + } + + ret = service_operation(new_op, __func__, + get_interruptible_flag(inode)); + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_inode_setattr: returning %d\n", + ret); + + /* when request is serviced properly, free req op struct */ + op_release(new_op); + + /* + * successful setattr should clear the atime, mtime and + * ctime flags. + */ + if (ret == 0) { + ClearAtimeFlag(orangefs_inode); + ClearMtimeFlag(orangefs_inode); + ClearCtimeFlag(orangefs_inode); + ClearModeFlag(orangefs_inode); + } + + return ret; +} + +int orangefs_flush_inode(struct inode *inode) +{ + /* + * If it is a dirty inode, this function gets called. + * Gather all the information that needs to be setattr'ed + * Right now, this will only be used for mode, atime, mtime + * and/or ctime. + */ + struct iattr wbattr; + int ret; + int mtime_flag; + int ctime_flag; + int atime_flag; + int mode_flag; + struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); + + memset(&wbattr, 0, sizeof(wbattr)); + + /* + * check inode flags up front, and clear them if they are set. This + * will prevent multiple processes from all trying to flush the same + * inode if they call close() simultaneously + */ + mtime_flag = MtimeFlag(orangefs_inode); + ClearMtimeFlag(orangefs_inode); + ctime_flag = CtimeFlag(orangefs_inode); + ClearCtimeFlag(orangefs_inode); + atime_flag = AtimeFlag(orangefs_inode); + ClearAtimeFlag(orangefs_inode); + mode_flag = ModeFlag(orangefs_inode); + ClearModeFlag(orangefs_inode); + + /* -- Lazy atime,mtime and ctime update -- + * Note: all times are dictated by server in the new scheme + * and not by the clients + * + * Also mode updates are being handled now.. + */ + + if (mtime_flag) + wbattr.ia_valid |= ATTR_MTIME; + if (ctime_flag) + wbattr.ia_valid |= ATTR_CTIME; + if (atime_flag) + wbattr.ia_valid |= ATTR_ATIME; + + if (mode_flag) { + wbattr.ia_mode = inode->i_mode; + wbattr.ia_valid |= ATTR_MODE; + } + + gossip_debug(GOSSIP_UTILS_DEBUG, + "*********** orangefs_flush_inode: %pU " + "(ia_valid %d)\n", + get_khandle_from_ino(inode), + wbattr.ia_valid); + if (wbattr.ia_valid == 0) { + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_flush_inode skipping setattr()\n"); + return 0; + } + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_flush_inode (%pU) writing mode %o\n", + get_khandle_from_ino(inode), + inode->i_mode); + + ret = orangefs_inode_setattr(inode, &wbattr); + + return ret; +} + +int orangefs_unmount_sb(struct super_block *sb) +{ + int ret = -EINVAL; + struct orangefs_kernel_op_s *new_op = NULL; + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_unmount_sb called on sb %p\n", + sb); + + new_op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT); + if (!new_op) + return -ENOMEM; + new_op->upcall.req.fs_umount.id = ORANGEFS_SB(sb)->id; + new_op->upcall.req.fs_umount.fs_id = ORANGEFS_SB(sb)->fs_id; + strncpy(new_op->upcall.req.fs_umount.orangefs_config_server, + ORANGEFS_SB(sb)->devname, + ORANGEFS_MAX_SERVER_ADDR_LEN); + + gossip_debug(GOSSIP_UTILS_DEBUG, + "Attempting ORANGEFS Unmount via host %s\n", + new_op->upcall.req.fs_umount.orangefs_config_server); + + ret = service_operation(new_op, "orangefs_fs_umount", 0); + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_unmount: got return value of %d\n", ret); + if (ret) + sb = ERR_PTR(ret); + else + ORANGEFS_SB(sb)->mount_pending = 1; + + op_release(new_op); + return ret; +} + +/* + * NOTE: on successful cancellation, be sure to return -EINTR, as + * that's the return value the caller expects + */ +int orangefs_cancel_op_in_progress(__u64 tag) +{ + int ret = -EINVAL; + struct orangefs_kernel_op_s *new_op = NULL; + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_cancel_op_in_progress called on tag %llu\n", + llu(tag)); + + new_op = op_alloc(ORANGEFS_VFS_OP_CANCEL); + if (!new_op) + return -ENOMEM; + new_op->upcall.req.cancel.op_tag = tag; + + gossip_debug(GOSSIP_UTILS_DEBUG, + "Attempting ORANGEFS operation cancellation of tag %llu\n", + llu(new_op->upcall.req.cancel.op_tag)); + + ret = service_operation(new_op, "orangefs_cancel", ORANGEFS_OP_CANCELLATION); + + gossip_debug(GOSSIP_UTILS_DEBUG, + "orangefs_cancel_op_in_progress: got return value of %d\n", + ret); + + op_release(new_op); + return ret; +} + +void orangefs_op_initialize(struct orangefs_kernel_op_s *op) +{ + if (op) { + spin_lock(&op->lock); + op->io_completed = 0; + + op->upcall.type = ORANGEFS_VFS_OP_INVALID; + op->downcall.type = ORANGEFS_VFS_OP_INVALID; + op->downcall.status = -1; + + op->op_state = OP_VFS_STATE_UNKNOWN; + op->tag = 0; + spin_unlock(&op->lock); + } +} + +void orangefs_make_bad_inode(struct inode *inode) +{ + if (is_root_handle(inode)) { + /* + * if this occurs, the pvfs2-client-core was killed but we + * can't afford to lose the inode operations and such + * associated with the root handle in any case. + */ + gossip_debug(GOSSIP_UTILS_DEBUG, + "*** NOT making bad root inode %pU\n", + get_khandle_from_ino(inode)); + } else { + gossip_debug(GOSSIP_UTILS_DEBUG, + "*** making bad inode %pU\n", + get_khandle_from_ino(inode)); + make_bad_inode(inode); + } +} + +/* Block all blockable signals... */ +void block_signals(sigset_t *orig_sigset) +{ + sigset_t mask; + + /* + * Initialize all entries in the signal set to the + * inverse of the given mask. + */ + siginitsetinv(&mask, sigmask(SIGKILL)); + + /* Block 'em Danno... */ + sigprocmask(SIG_BLOCK, &mask, orig_sigset); +} + +/* set the signal mask to the given template... */ +void set_signals(sigset_t *sigset) +{ + sigprocmask(SIG_SETMASK, sigset, NULL); +} + +/* + * The following is a very dirty hack that is now a permanent part of the + * ORANGEFS protocol. See protocol.h for more error definitions. + */ + +/* The order matches include/orangefs-types.h in the OrangeFS source. */ +static int PINT_errno_mapping[] = { + 0, EPERM, ENOENT, EINTR, EIO, ENXIO, EBADF, EAGAIN, ENOMEM, + EFAULT, EBUSY, EEXIST, ENODEV, ENOTDIR, EISDIR, EINVAL, EMFILE, + EFBIG, ENOSPC, EROFS, EMLINK, EPIPE, EDEADLK, ENAMETOOLONG, + ENOLCK, ENOSYS, ENOTEMPTY, ELOOP, EWOULDBLOCK, ENOMSG, EUNATCH, + EBADR, EDEADLOCK, ENODATA, ETIME, ENONET, EREMOTE, ECOMM, + EPROTO, EBADMSG, EOVERFLOW, ERESTART, EMSGSIZE, EPROTOTYPE, + ENOPROTOOPT, EPROTONOSUPPORT, EOPNOTSUPP, EADDRINUSE, + EADDRNOTAVAIL, ENETDOWN, ENETUNREACH, ENETRESET, ENOBUFS, + ETIMEDOUT, ECONNREFUSED, EHOSTDOWN, EHOSTUNREACH, EALREADY, + EACCES, ECONNRESET, ERANGE +}; + +int orangefs_normalize_to_errno(__s32 error_code) +{ + __u32 i; + + /* Success */ + if (error_code == 0) { + return 0; + /* + * This shouldn't ever happen. If it does it should be fixed on the + * server. + */ + } else if (error_code > 0) { + gossip_err("orangefs: error status receieved.\n"); + gossip_err("orangefs: assuming error code is inverted.\n"); + error_code = -error_code; + } + + /* + * XXX: This is very bad since error codes from ORANGEFS may not be + * suitable for return into userspace. + */ + + /* + * Convert ORANGEFS error values into errno values suitable for return + * from the kernel. + */ + if ((-error_code) & ORANGEFS_NON_ERRNO_ERROR_BIT) { + if (((-error_code) & + (ORANGEFS_ERROR_NUMBER_BITS|ORANGEFS_NON_ERRNO_ERROR_BIT| + ORANGEFS_ERROR_BIT)) == ORANGEFS_ECANCEL) { + /* + * cancellation error codes generally correspond to + * a timeout from the client's perspective + */ + error_code = -ETIMEDOUT; + } else { + /* assume a default error code */ + gossip_err("orangefs: warning: got error code without errno equivalent: %d.\n", error_code); + error_code = -EINVAL; + } + + /* Convert ORANGEFS encoded errno values into regular errno values. */ + } else if ((-error_code) & ORANGEFS_ERROR_BIT) { + i = (-error_code) & ~(ORANGEFS_ERROR_BIT|ORANGEFS_ERROR_CLASS_BITS); + if (i < sizeof(PINT_errno_mapping)/sizeof(*PINT_errno_mapping)) + error_code = -PINT_errno_mapping[i]; + else + error_code = -EINVAL; + + /* + * Only ORANGEFS protocol error codes should ever come here. Otherwise + * there is a bug somewhere. + */ + } else { + gossip_err("orangefs: orangefs_normalize_to_errno: got error code which is not from ORANGEFS.\n"); + } + return error_code; +} + +#define NUM_MODES 11 +__s32 ORANGEFS_util_translate_mode(int mode) +{ + int ret = 0; + int i = 0; + static int modes[NUM_MODES] = { + S_IXOTH, S_IWOTH, S_IROTH, + S_IXGRP, S_IWGRP, S_IRGRP, + S_IXUSR, S_IWUSR, S_IRUSR, + S_ISGID, S_ISUID + }; + static int orangefs_modes[NUM_MODES] = { + ORANGEFS_O_EXECUTE, ORANGEFS_O_WRITE, ORANGEFS_O_READ, + ORANGEFS_G_EXECUTE, ORANGEFS_G_WRITE, ORANGEFS_G_READ, + ORANGEFS_U_EXECUTE, ORANGEFS_U_WRITE, ORANGEFS_U_READ, + ORANGEFS_G_SGID, ORANGEFS_U_SUID + }; + + for (i = 0; i < NUM_MODES; i++) + if (mode & modes[i]) + ret |= orangefs_modes[i]; + + return ret; +} +#undef NUM_MODES + +/* + * After obtaining a string representation of the client's debug + * keywords and their associated masks, this function is called to build an + * array of these values. + */ +int orangefs_prepare_cdm_array(char *debug_array_string) +{ + int i; + int rc = -EINVAL; + char *cds_head = NULL; + char *cds_delimiter = NULL; + int keyword_len = 0; + + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); + + /* + * figure out how many elements the cdm_array needs. + */ + for (i = 0; i < strlen(debug_array_string); i++) + if (debug_array_string[i] == '\n') + cdm_element_count++; + + if (!cdm_element_count) { + pr_info("No elements in client debug array string!\n"); + goto out; + } + + cdm_array = + kzalloc(cdm_element_count * sizeof(struct client_debug_mask), + GFP_KERNEL); + if (!cdm_array) { + pr_info("malloc failed for cdm_array!\n"); + rc = -ENOMEM; + goto out; + } + + cds_head = debug_array_string; + + for (i = 0; i < cdm_element_count; i++) { + cds_delimiter = strchr(cds_head, '\n'); + *cds_delimiter = '\0'; + + keyword_len = strcspn(cds_head, " "); + + cdm_array[i].keyword = kzalloc(keyword_len + 1, GFP_KERNEL); + if (!cdm_array[i].keyword) { + rc = -ENOMEM; + goto out; + } + + sscanf(cds_head, + "%s %llx %llx", + cdm_array[i].keyword, + (unsigned long long *)&(cdm_array[i].mask1), + (unsigned long long *)&(cdm_array[i].mask2)); + + if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE)) + client_verbose_index = i; + + if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL)) + client_all_index = i; + + cds_head = cds_delimiter + 1; + } + + rc = cdm_element_count; + + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n", __func__, rc); + +out: + + return rc; + +} + +/* + * /sys/kernel/debug/orangefs/debug-help can be catted to + * see all the available kernel and client debug keywords. + * + * When the kernel boots, we have no idea what keywords the + * client supports, nor their associated masks. + * + * We pass through this function once at boot and stamp a + * boilerplate "we don't know" message for the client in the + * debug-help file. We pass through here again when the client + * starts and then we can fill out the debug-help file fully. + * + * The client might be restarted any number of times between + * reboots, we only build the debug-help file the first time. + */ +int orangefs_prepare_debugfs_help_string(int at_boot) +{ + int rc = -EINVAL; + int i; + int byte_count = 0; + char *client_title = "Client Debug Keywords:\n"; + char *kernel_title = "Kernel Debug Keywords:\n"; + + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); + + if (at_boot) { + byte_count += strlen(HELP_STRING_UNINITIALIZED); + client_title = HELP_STRING_UNINITIALIZED; + } else { + /* + * fill the client keyword/mask array and remember + * how many elements there were. + */ + cdm_element_count = + orangefs_prepare_cdm_array(client_debug_array_string); + if (cdm_element_count <= 0) + goto out; + + /* Count the bytes destined for debug_help_string. */ + byte_count += strlen(client_title); + + for (i = 0; i < cdm_element_count; i++) { + byte_count += strlen(cdm_array[i].keyword + 2); + if (byte_count >= DEBUG_HELP_STRING_SIZE) { + pr_info("%s: overflow 1!\n", __func__); + goto out; + } + } + + gossip_debug(GOSSIP_UTILS_DEBUG, + "%s: cdm_element_count:%d:\n", + __func__, + cdm_element_count); + } + + byte_count += strlen(kernel_title); + for (i = 0; i < num_kmod_keyword_mask_map; i++) { + byte_count += + strlen(s_kmod_keyword_mask_map[i].keyword + 2); + if (byte_count >= DEBUG_HELP_STRING_SIZE) { + pr_info("%s: overflow 2!\n", __func__); + goto out; + } + } + + /* build debug_help_string. */ + debug_help_string = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL); + if (!debug_help_string) { + rc = -ENOMEM; + goto out; + } + + strcat(debug_help_string, client_title); + + if (!at_boot) { + for (i = 0; i < cdm_element_count; i++) { + strcat(debug_help_string, "\t"); + strcat(debug_help_string, cdm_array[i].keyword); + strcat(debug_help_string, "\n"); + } + } + + strcat(debug_help_string, "\n"); + strcat(debug_help_string, kernel_title); + + for (i = 0; i < num_kmod_keyword_mask_map; i++) { + strcat(debug_help_string, "\t"); + strcat(debug_help_string, s_kmod_keyword_mask_map[i].keyword); + strcat(debug_help_string, "\n"); + } + + rc = 0; + +out: + + return rc; + +} + +/* + * kernel = type 0 + * client = type 1 + */ +void debug_mask_to_string(void *mask, int type) +{ + int i; + int len = 0; + char *debug_string; + int element_count = 0; + + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); + + if (type) { + debug_string = client_debug_string; + element_count = cdm_element_count; + } else { + debug_string = kernel_debug_string; + element_count = num_kmod_keyword_mask_map; + } + + memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); + + /* + * Some keywords, like "all" or "verbose", are amalgams of + * numerous other keywords. Make a special check for those + * before grinding through the whole mask only to find out + * later... + */ + if (check_amalgam_keyword(mask, type)) + goto out; + + /* Build the debug string. */ + for (i = 0; i < element_count; i++) + if (type) + do_c_string(mask, i); + else + do_k_string(mask, i); + + len = strlen(debug_string); + + if ((len) && (type)) + client_debug_string[len - 1] = '\0'; + else if (len) + kernel_debug_string[len - 1] = '\0'; + else if (type) + strcpy(client_debug_string, "none"); + else + strcpy(kernel_debug_string, "none"); + +out: +gossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n", __func__, debug_string); + + return; + +} + +void do_k_string(void *k_mask, int index) +{ + __u64 *mask = (__u64 *) k_mask; + + if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword)) + goto out; + + if (*mask & s_kmod_keyword_mask_map[index].mask_val) { + if ((strlen(kernel_debug_string) + + strlen(s_kmod_keyword_mask_map[index].keyword)) + < ORANGEFS_MAX_DEBUG_STRING_LEN - 1) { + strcat(kernel_debug_string, + s_kmod_keyword_mask_map[index].keyword); + strcat(kernel_debug_string, ","); + } else { + gossip_err("%s: overflow!\n", __func__); + strcpy(kernel_debug_string, ORANGEFS_ALL); + goto out; + } + } + +out: + + return; +} + +void do_c_string(void *c_mask, int index) +{ + struct client_debug_mask *mask = (struct client_debug_mask *) c_mask; + + if (keyword_is_amalgam(cdm_array[index].keyword)) + goto out; + + if ((mask->mask1 & cdm_array[index].mask1) || + (mask->mask2 & cdm_array[index].mask2)) { + if ((strlen(client_debug_string) + + strlen(cdm_array[index].keyword) + 1) + < ORANGEFS_MAX_DEBUG_STRING_LEN - 2) { + strcat(client_debug_string, + cdm_array[index].keyword); + strcat(client_debug_string, ","); + } else { + gossip_err("%s: overflow!\n", __func__); + strcpy(client_debug_string, ORANGEFS_ALL); + goto out; + } + } +out: + return; +} + +int keyword_is_amalgam(char *keyword) +{ + int rc = 0; + + if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE))) + rc = 1; + + return rc; +} + +/* + * kernel = type 0 + * client = type 1 + * + * return 1 if we found an amalgam. + */ +int check_amalgam_keyword(void *mask, int type) +{ + __u64 *k_mask; + struct client_debug_mask *c_mask; + int k_all_index = num_kmod_keyword_mask_map - 1; + int rc = 0; + + if (type) { + c_mask = (struct client_debug_mask *) mask; + + if ((c_mask->mask1 == cdm_array[client_all_index].mask1) && + (c_mask->mask2 == cdm_array[client_all_index].mask2)) { + strcpy(client_debug_string, ORANGEFS_ALL); + rc = 1; + goto out; + } + + if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) && + (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) { + strcpy(client_debug_string, ORANGEFS_VERBOSE); + rc = 1; + goto out; + } + + } else { + k_mask = (__u64 *) mask; + + if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) { + strcpy(kernel_debug_string, ORANGEFS_ALL); + rc = 1; + goto out; + } + } + +out: + + return rc; +} + +/* + * kernel = type 0 + * client = type 1 + */ +void debug_string_to_mask(char *debug_string, void *mask, int type) +{ + char *unchecked_keyword; + int i; + char *strsep_fodder = kstrdup(debug_string, GFP_KERNEL); + char *original_pointer; + int element_count = 0; + struct client_debug_mask *c_mask; + __u64 *k_mask; + + gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); + + if (type) { + c_mask = (struct client_debug_mask *)mask; + element_count = cdm_element_count; + } else { + k_mask = (__u64 *)mask; + *k_mask = 0; + element_count = num_kmod_keyword_mask_map; + } + + original_pointer = strsep_fodder; + while ((unchecked_keyword = strsep(&strsep_fodder, ","))) + if (strlen(unchecked_keyword)) { + for (i = 0; i < element_count; i++) + if (type) + do_c_mask(i, + unchecked_keyword, + &c_mask); + else + do_k_mask(i, + unchecked_keyword, + &k_mask); + } + + kfree(original_pointer); +} + +void do_c_mask(int i, + char *unchecked_keyword, + struct client_debug_mask **sane_mask) +{ + + if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) { + (**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1; + (**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2; + } +} + +void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask) +{ + + if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword)) + **sane_mask = (**sane_mask) | + s_kmod_keyword_mask_map[i].mask_val; +} diff --git a/fs/orangefs/protocol.h b/fs/orangefs/protocol.h index 5f10ebc83e76..03bbe7505a35 100644 --- a/fs/orangefs/protocol.h +++ b/fs/orangefs/protocol.h @@ -130,7 +130,7 @@ typedef __s64 ORANGEFS_offset; /* Bits 6 - 0 are reserved for the actual error code. */ #define ORANGEFS_ERROR_NUMBER_BITS 0x7f -/* Encoded errno values are decoded by PINT_errno_mapping in pvfs2-utils.c. */ +/* Encoded errno values decoded by PINT_errno_mapping in orangefs-utils.c. */ /* Our own ORANGEFS protocol error codes. */ #define ORANGEFS_ECANCEL (1|ORANGEFS_NON_ERRNO_ERROR_BIT|ORANGEFS_ERROR_BIT) @@ -352,7 +352,7 @@ struct dev_mask2_info_s { __s32 ORANGEFS_util_translate_mode(int mode); /* pvfs2-debug.h ************************************************************/ -#include "pvfs2-debug.h" +#include "orangefs-debug.h" /* pvfs2-internal.h *********************************************************/ #define llu(x) (unsigned long long)(x) @@ -402,7 +402,7 @@ enum { /* * describes memory regions to map in the ORANGEFS_DEV_MAP ioctl. - * NOTE: See devpvfs2-req.c for 32 bit compat structure. + * NOTE: See devorangefs-req.c for 32 bit compat structure. * Since this structure has a variable-sized layout that is different * on 32 and 64 bit platforms, we need to normalize to a 64 bit layout * on such systems before servicing ioctl calls from user-space binaries diff --git a/fs/orangefs/pvfs2-bufmap.c b/fs/orangefs/pvfs2-bufmap.c deleted file mode 100644 index 345287e871b1..000000000000 --- a/fs/orangefs/pvfs2-bufmap.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ -#include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" - -DECLARE_WAIT_QUEUE_HEAD(orangefs_bufmap_init_waitq); - -static struct orangefs_bufmap { - atomic_t refcnt; - - int desc_size; - int desc_shift; - int desc_count; - int total_size; - int page_count; - - struct page **page_array; - struct orangefs_bufmap_desc *desc_array; - - /* array to track usage of buffer descriptors */ - int *buffer_index_array; - spinlock_t buffer_index_lock; - - /* array to track usage of buffer descriptors for readdir */ - int readdir_index_array[ORANGEFS_READDIR_DEFAULT_DESC_COUNT]; - spinlock_t readdir_index_lock; -} *__orangefs_bufmap; - -static DEFINE_SPINLOCK(orangefs_bufmap_lock); - -static void -orangefs_bufmap_unmap(struct orangefs_bufmap *bufmap) -{ - int i; - - for (i = 0; i < bufmap->page_count; i++) - page_cache_release(bufmap->page_array[i]); -} - -static void -orangefs_bufmap_free(struct orangefs_bufmap *bufmap) -{ - kfree(bufmap->page_array); - kfree(bufmap->desc_array); - kfree(bufmap->buffer_index_array); - kfree(bufmap); -} - -struct orangefs_bufmap *orangefs_bufmap_ref(void) -{ - struct orangefs_bufmap *bufmap = NULL; - - spin_lock(&orangefs_bufmap_lock); - if (__orangefs_bufmap) { - bufmap = __orangefs_bufmap; - atomic_inc(&bufmap->refcnt); - } - spin_unlock(&orangefs_bufmap_lock); - return bufmap; -} - -void orangefs_bufmap_unref(struct orangefs_bufmap *bufmap) -{ - if (atomic_dec_and_lock(&bufmap->refcnt, &orangefs_bufmap_lock)) { - __orangefs_bufmap = NULL; - spin_unlock(&orangefs_bufmap_lock); - - orangefs_bufmap_unmap(bufmap); - orangefs_bufmap_free(bufmap); - } -} - -inline int orangefs_bufmap_size_query(void) -{ - struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); - int size = bufmap ? bufmap->desc_size : 0; - - orangefs_bufmap_unref(bufmap); - return size; -} - -inline int orangefs_bufmap_shift_query(void) -{ - struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); - int shift = bufmap ? bufmap->desc_shift : 0; - - orangefs_bufmap_unref(bufmap); - return shift; -} - -static DECLARE_WAIT_QUEUE_HEAD(bufmap_waitq); -static DECLARE_WAIT_QUEUE_HEAD(readdir_waitq); - -/* - * get_bufmap_init - * - * If bufmap_init is 1, then the shared memory system, including the - * buffer_index_array, is available. Otherwise, it is not. - * - * returns the value of bufmap_init - */ -int get_bufmap_init(void) -{ - return __orangefs_bufmap ? 1 : 0; -} - - -static struct orangefs_bufmap * -orangefs_bufmap_alloc(struct ORANGEFS_dev_map_desc *user_desc) -{ - struct orangefs_bufmap *bufmap; - - bufmap = kzalloc(sizeof(*bufmap), GFP_KERNEL); - if (!bufmap) - goto out; - - atomic_set(&bufmap->refcnt, 1); - bufmap->total_size = user_desc->total_size; - bufmap->desc_count = user_desc->count; - bufmap->desc_size = user_desc->size; - bufmap->desc_shift = ilog2(bufmap->desc_size); - - spin_lock_init(&bufmap->buffer_index_lock); - bufmap->buffer_index_array = - kcalloc(bufmap->desc_count, sizeof(int), GFP_KERNEL); - if (!bufmap->buffer_index_array) { - gossip_err("orangefs: could not allocate %d buffer indices\n", - bufmap->desc_count); - goto out_free_bufmap; - } - spin_lock_init(&bufmap->readdir_index_lock); - - bufmap->desc_array = - kcalloc(bufmap->desc_count, sizeof(struct orangefs_bufmap_desc), - GFP_KERNEL); - if (!bufmap->desc_array) { - gossip_err("orangefs: could not allocate %d descriptors\n", - bufmap->desc_count); - goto out_free_index_array; - } - - bufmap->page_count = bufmap->total_size / PAGE_SIZE; - - /* allocate storage to track our page mappings */ - bufmap->page_array = - kcalloc(bufmap->page_count, sizeof(struct page *), GFP_KERNEL); - if (!bufmap->page_array) - goto out_free_desc_array; - - return bufmap; - -out_free_desc_array: - kfree(bufmap->desc_array); -out_free_index_array: - kfree(bufmap->buffer_index_array); -out_free_bufmap: - kfree(bufmap); -out: - return NULL; -} - -static int -orangefs_bufmap_map(struct orangefs_bufmap *bufmap, - struct ORANGEFS_dev_map_desc *user_desc) -{ - int pages_per_desc = bufmap->desc_size / PAGE_SIZE; - int offset = 0, ret, i; - - /* map the pages */ - ret = get_user_pages_fast((unsigned long)user_desc->ptr, - bufmap->page_count, 1, bufmap->page_array); - - if (ret < 0) - return ret; - - if (ret != bufmap->page_count) { - gossip_err("orangefs error: asked for %d pages, only got %d.\n", - bufmap->page_count, ret); - - for (i = 0; i < ret; i++) { - SetPageError(bufmap->page_array[i]); - page_cache_release(bufmap->page_array[i]); - } - return -ENOMEM; - } - - /* - * ideally we want to get kernel space pointers for each page, but - * we can't kmap that many pages at once if highmem is being used. - * so instead, we just kmap/kunmap the page address each time the - * kaddr is needed. - */ - for (i = 0; i < bufmap->page_count; i++) - flush_dcache_page(bufmap->page_array[i]); - - /* build a list of available descriptors */ - for (offset = 0, i = 0; i < bufmap->desc_count; i++) { - bufmap->desc_array[i].page_array = &bufmap->page_array[offset]; - bufmap->desc_array[i].array_count = pages_per_desc; - bufmap->desc_array[i].uaddr = - (user_desc->ptr + (i * pages_per_desc * PAGE_SIZE)); - offset += pages_per_desc; - } - - return 0; -} - -/* - * orangefs_bufmap_initialize() - * - * initializes the mapped buffer interface - * - * returns 0 on success, -errno on failure - */ -int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc) -{ - struct orangefs_bufmap *bufmap; - int ret = -EINVAL; - - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "orangefs_bufmap_initialize: called (ptr (" - "%p) sz (%d) cnt(%d).\n", - user_desc->ptr, - user_desc->size, - user_desc->count); - - /* - * sanity check alignment and size of buffer that caller wants to - * work with - */ - if (PAGE_ALIGN((unsigned long)user_desc->ptr) != - (unsigned long)user_desc->ptr) { - gossip_err("orangefs error: memory alignment (front). %p\n", - user_desc->ptr); - goto out; - } - - if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->total_size)) - != (unsigned long)(user_desc->ptr + user_desc->total_size)) { - gossip_err("orangefs error: memory alignment (back).(%p + %d)\n", - user_desc->ptr, - user_desc->total_size); - goto out; - } - - if (user_desc->total_size != (user_desc->size * user_desc->count)) { - gossip_err("orangefs error: user provided an oddly sized buffer: (%d, %d, %d)\n", - user_desc->total_size, - user_desc->size, - user_desc->count); - goto out; - } - - if ((user_desc->size % PAGE_SIZE) != 0) { - gossip_err("orangefs error: bufmap size not page size divisible (%d).\n", - user_desc->size); - goto out; - } - - ret = -ENOMEM; - bufmap = orangefs_bufmap_alloc(user_desc); - if (!bufmap) - goto out; - - ret = orangefs_bufmap_map(bufmap, user_desc); - if (ret) - goto out_free_bufmap; - - - spin_lock(&orangefs_bufmap_lock); - if (__orangefs_bufmap) { - spin_unlock(&orangefs_bufmap_lock); - gossip_err("orangefs: error: bufmap already initialized.\n"); - ret = -EALREADY; - goto out_unmap_bufmap; - } - __orangefs_bufmap = bufmap; - spin_unlock(&orangefs_bufmap_lock); - - /* - * If there are operations in orangefs_bufmap_init_waitq, wake them up. - * This scenario occurs when the client-core is restarted and I/O - * requests in the in-progress or waiting tables are restarted. I/O - * requests cannot be restarted until the shared memory system is - * completely re-initialized, so we put the I/O requests in this - * waitq until initialization has completed. NOTE: the I/O requests - * are also on a timer, so they don't wait forever just in case the - * client-core doesn't come back up. - */ - wake_up_interruptible(&orangefs_bufmap_init_waitq); - - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "orangefs_bufmap_initialize: exiting normally\n"); - return 0; - -out_unmap_bufmap: - orangefs_bufmap_unmap(bufmap); -out_free_bufmap: - orangefs_bufmap_free(bufmap); -out: - return ret; -} - -/* - * orangefs_bufmap_finalize() - * - * shuts down the mapped buffer interface and releases any resources - * associated with it - * - * no return value - */ -void orangefs_bufmap_finalize(void) -{ - gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs_bufmap_finalize: called\n"); - BUG_ON(!__orangefs_bufmap); - orangefs_bufmap_unref(__orangefs_bufmap); - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "orangefs_bufmap_finalize: exiting normally\n"); -} - -struct slot_args { - int slot_count; - int *slot_array; - spinlock_t *slot_lock; - wait_queue_head_t *slot_wq; -}; - -static int wait_for_a_slot(struct slot_args *slargs, int *buffer_index) -{ - int ret = -1; - int i = 0; - DECLARE_WAITQUEUE(my_wait, current); - - - add_wait_queue_exclusive(slargs->slot_wq, &my_wait); - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - - /* - * check for available desc, slot_lock is the appropriate - * index_lock - */ - spin_lock(slargs->slot_lock); - for (i = 0; i < slargs->slot_count; i++) - if (slargs->slot_array[i] == 0) { - slargs->slot_array[i] = 1; - *buffer_index = i; - ret = 0; - break; - } - spin_unlock(slargs->slot_lock); - - /* if we acquired a buffer, then break out of while */ - if (ret == 0) - break; - - if (!signal_pending(current)) { - int timeout = - MSECS_TO_JIFFIES(1000 * slot_timeout_secs); - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "[BUFMAP]: waiting %d " - "seconds for a slot\n", - slot_timeout_secs); - if (!schedule_timeout(timeout)) { - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "*** wait_for_a_slot timed out\n"); - ret = -ETIMEDOUT; - break; - } - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "[BUFMAP]: woken up by a slot becoming available.\n"); - continue; - } - - gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs: %s interrupted.\n", - __func__); - ret = -EINTR; - break; - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(slargs->slot_wq, &my_wait); - return ret; -} - -static void put_back_slot(struct slot_args *slargs, int buffer_index) -{ - /* slot_lock is the appropriate index_lock */ - spin_lock(slargs->slot_lock); - if (buffer_index < 0 || buffer_index >= slargs->slot_count) { - spin_unlock(slargs->slot_lock); - return; - } - - /* put the desc back on the queue */ - slargs->slot_array[buffer_index] = 0; - spin_unlock(slargs->slot_lock); - - /* wake up anyone who may be sleeping on the queue */ - wake_up_interruptible(slargs->slot_wq); -} - -/* - * orangefs_bufmap_get() - * - * gets a free mapped buffer descriptor, will sleep until one becomes - * available if necessary - * - * returns 0 on success, -errno on failure - */ -int orangefs_bufmap_get(struct orangefs_bufmap **mapp, int *buffer_index) -{ - struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); - struct slot_args slargs; - int ret; - - if (!bufmap) { - gossip_err("orangefs: please confirm that pvfs2-client daemon is running.\n"); - return -EIO; - } - - slargs.slot_count = bufmap->desc_count; - slargs.slot_array = bufmap->buffer_index_array; - slargs.slot_lock = &bufmap->buffer_index_lock; - slargs.slot_wq = &bufmap_waitq; - ret = wait_for_a_slot(&slargs, buffer_index); - if (ret) - orangefs_bufmap_unref(bufmap); - *mapp = bufmap; - return ret; -} - -/* - * orangefs_bufmap_put() - * - * returns a mapped buffer descriptor to the collection - * - * no return value - */ -void orangefs_bufmap_put(struct orangefs_bufmap *bufmap, int buffer_index) -{ - struct slot_args slargs; - - slargs.slot_count = bufmap->desc_count; - slargs.slot_array = bufmap->buffer_index_array; - slargs.slot_lock = &bufmap->buffer_index_lock; - slargs.slot_wq = &bufmap_waitq; - put_back_slot(&slargs, buffer_index); - orangefs_bufmap_unref(bufmap); -} - -/* - * readdir_index_get() - * - * gets a free descriptor, will sleep until one becomes - * available if necessary. - * Although the readdir buffers are not mapped into kernel space - * we could do that at a later point of time. Regardless, these - * indices are used by the client-core. - * - * returns 0 on success, -errno on failure - */ -int readdir_index_get(struct orangefs_bufmap **mapp, int *buffer_index) -{ - struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); - struct slot_args slargs; - int ret; - - if (!bufmap) { - gossip_err("orangefs: please confirm that pvfs2-client daemon is running.\n"); - return -EIO; - } - - slargs.slot_count = ORANGEFS_READDIR_DEFAULT_DESC_COUNT; - slargs.slot_array = bufmap->readdir_index_array; - slargs.slot_lock = &bufmap->readdir_index_lock; - slargs.slot_wq = &readdir_waitq; - ret = wait_for_a_slot(&slargs, buffer_index); - if (ret) - orangefs_bufmap_unref(bufmap); - *mapp = bufmap; - return ret; -} - -void readdir_index_put(struct orangefs_bufmap *bufmap, int buffer_index) -{ - struct slot_args slargs; - - slargs.slot_count = ORANGEFS_READDIR_DEFAULT_DESC_COUNT; - slargs.slot_array = bufmap->readdir_index_array; - slargs.slot_lock = &bufmap->readdir_index_lock; - slargs.slot_wq = &readdir_waitq; - put_back_slot(&slargs, buffer_index); - orangefs_bufmap_unref(bufmap); -} - -int orangefs_bufmap_copy_from_iovec(struct orangefs_bufmap *bufmap, - struct iov_iter *iter, - int buffer_index, - size_t size) -{ - struct orangefs_bufmap_desc *to = &bufmap->desc_array[buffer_index]; - int i; - - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "%s: buffer_index:%d: size:%zu:\n", - __func__, buffer_index, size); - - - for (i = 0; size; i++) { - struct page *page = to->page_array[i]; - size_t n = size; - if (n > PAGE_SIZE) - n = PAGE_SIZE; - n = copy_page_from_iter(page, 0, n, iter); - if (!n) - return -EFAULT; - size -= n; - } - return 0; - -} - -/* - * Iterate through the array of pages containing the bytes from - * a file being read. - * - */ -int orangefs_bufmap_copy_to_iovec(struct orangefs_bufmap *bufmap, - struct iov_iter *iter, - int buffer_index, - size_t size) -{ - struct orangefs_bufmap_desc *from = &bufmap->desc_array[buffer_index]; - int i; - - gossip_debug(GOSSIP_BUFMAP_DEBUG, - "%s: buffer_index:%d: size:%zu:\n", - __func__, buffer_index, size); - - - for (i = 0; size; i++) { - struct page *page = from->page_array[i]; - size_t n = size; - if (n > PAGE_SIZE) - n = PAGE_SIZE; - n = copy_page_to_iter(page, 0, n, iter); - if (!n) - return -EFAULT; - size -= n; - } - return 0; -} diff --git a/fs/orangefs/pvfs2-bufmap.h b/fs/orangefs/pvfs2-bufmap.h deleted file mode 100644 index 91d1755c231a..000000000000 --- a/fs/orangefs/pvfs2-bufmap.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ - -#ifndef __ORANGEFS_BUFMAP_H -#define __ORANGEFS_BUFMAP_H - -/* used to describe mapped buffers */ -struct orangefs_bufmap_desc { - void *uaddr; /* user space address pointer */ - struct page **page_array; /* array of mapped pages */ - int array_count; /* size of above arrays */ - struct list_head list_link; -}; - -struct orangefs_bufmap; - -struct orangefs_bufmap *orangefs_bufmap_ref(void); -void orangefs_bufmap_unref(struct orangefs_bufmap *bufmap); - -/* - * orangefs_bufmap_size_query is now an inline function because buffer - * sizes are not hardcoded - */ -int orangefs_bufmap_size_query(void); - -int orangefs_bufmap_shift_query(void); - -int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc); - -int get_bufmap_init(void); - -void orangefs_bufmap_finalize(void); - -int orangefs_bufmap_get(struct orangefs_bufmap **mapp, int *buffer_index); - -void orangefs_bufmap_put(struct orangefs_bufmap *bufmap, int buffer_index); - -int readdir_index_get(struct orangefs_bufmap **mapp, int *buffer_index); - -void readdir_index_put(struct orangefs_bufmap *bufmap, int buffer_index); - -int orangefs_bufmap_copy_from_iovec(struct orangefs_bufmap *bufmap, - struct iov_iter *iter, - int buffer_index, - size_t size); - -int orangefs_bufmap_copy_to_iovec(struct orangefs_bufmap *bufmap, - struct iov_iter *iter, - int buffer_index, - size_t size); - -size_t orangefs_bufmap_copy_to_user_task_iovec(struct task_struct *tsk, - struct iovec *iovec, - unsigned long nr_segs, - struct orangefs_bufmap *bufmap, - int buffer_index, - size_t bytes_to_be_copied); - -#endif /* __ORANGEFS_BUFMAP_H */ diff --git a/fs/orangefs/pvfs2-cache.c b/fs/orangefs/pvfs2-cache.c deleted file mode 100644 index a224831770f4..000000000000 --- a/fs/orangefs/pvfs2-cache.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ - -#include "protocol.h" -#include "pvfs2-kernel.h" - -/* tags assigned to kernel upcall operations */ -static __u64 next_tag_value; -static DEFINE_SPINLOCK(next_tag_value_lock); - -/* the orangefs memory caches */ - -/* a cache for orangefs upcall/downcall operations */ -static struct kmem_cache *op_cache; - -/* a cache for device (/dev/pvfs2-req) communication */ -static struct kmem_cache *dev_req_cache; - -/* a cache for orangefs_kiocb objects (i.e orangefs iocb structures ) */ -static struct kmem_cache *orangefs_kiocb_cache; - -int op_cache_initialize(void) -{ - op_cache = kmem_cache_create("orangefs_op_cache", - sizeof(struct orangefs_kernel_op_s), - 0, - ORANGEFS_CACHE_CREATE_FLAGS, - NULL); - - if (!op_cache) { - gossip_err("Cannot create orangefs_op_cache\n"); - return -ENOMEM; - } - - /* initialize our atomic tag counter */ - spin_lock(&next_tag_value_lock); - next_tag_value = 100; - spin_unlock(&next_tag_value_lock); - return 0; -} - -int op_cache_finalize(void) -{ - kmem_cache_destroy(op_cache); - return 0; -} - -char *get_opname_string(struct orangefs_kernel_op_s *new_op) -{ - if (new_op) { - __s32 type = new_op->upcall.type; - - if (type == ORANGEFS_VFS_OP_FILE_IO) - return "OP_FILE_IO"; - else if (type == ORANGEFS_VFS_OP_LOOKUP) - return "OP_LOOKUP"; - else if (type == ORANGEFS_VFS_OP_CREATE) - return "OP_CREATE"; - else if (type == ORANGEFS_VFS_OP_GETATTR) - return "OP_GETATTR"; - else if (type == ORANGEFS_VFS_OP_REMOVE) - return "OP_REMOVE"; - else if (type == ORANGEFS_VFS_OP_MKDIR) - return "OP_MKDIR"; - else if (type == ORANGEFS_VFS_OP_READDIR) - return "OP_READDIR"; - else if (type == ORANGEFS_VFS_OP_READDIRPLUS) - return "OP_READDIRPLUS"; - else if (type == ORANGEFS_VFS_OP_SETATTR) - return "OP_SETATTR"; - else if (type == ORANGEFS_VFS_OP_SYMLINK) - return "OP_SYMLINK"; - else if (type == ORANGEFS_VFS_OP_RENAME) - return "OP_RENAME"; - else if (type == ORANGEFS_VFS_OP_STATFS) - return "OP_STATFS"; - else if (type == ORANGEFS_VFS_OP_TRUNCATE) - return "OP_TRUNCATE"; - else if (type == ORANGEFS_VFS_OP_MMAP_RA_FLUSH) - return "OP_MMAP_RA_FLUSH"; - else if (type == ORANGEFS_VFS_OP_FS_MOUNT) - return "OP_FS_MOUNT"; - else if (type == ORANGEFS_VFS_OP_FS_UMOUNT) - return "OP_FS_UMOUNT"; - else if (type == ORANGEFS_VFS_OP_GETXATTR) - return "OP_GETXATTR"; - else if (type == ORANGEFS_VFS_OP_SETXATTR) - return "OP_SETXATTR"; - else if (type == ORANGEFS_VFS_OP_LISTXATTR) - return "OP_LISTXATTR"; - else if (type == ORANGEFS_VFS_OP_REMOVEXATTR) - return "OP_REMOVEXATTR"; - else if (type == ORANGEFS_VFS_OP_PARAM) - return "OP_PARAM"; - else if (type == ORANGEFS_VFS_OP_PERF_COUNT) - return "OP_PERF_COUNT"; - else if (type == ORANGEFS_VFS_OP_CANCEL) - return "OP_CANCEL"; - else if (type == ORANGEFS_VFS_OP_FSYNC) - return "OP_FSYNC"; - else if (type == ORANGEFS_VFS_OP_FSKEY) - return "OP_FSKEY"; - } - return "OP_UNKNOWN?"; -} - -struct orangefs_kernel_op_s *op_alloc(__s32 type) -{ - struct orangefs_kernel_op_s *new_op = NULL; - - new_op = kmem_cache_alloc(op_cache, ORANGEFS_CACHE_ALLOC_FLAGS); - if (new_op) { - memset(new_op, 0, sizeof(struct orangefs_kernel_op_s)); - - INIT_LIST_HEAD(&new_op->list); - spin_lock_init(&new_op->lock); - init_waitqueue_head(&new_op->waitq); - - init_waitqueue_head(&new_op->io_completion_waitq); - atomic_set(&new_op->aio_ref_count, 0); - - orangefs_op_initialize(new_op); - - /* initialize the op specific tag and upcall credentials */ - spin_lock(&next_tag_value_lock); - new_op->tag = next_tag_value++; - if (next_tag_value == 0) - next_tag_value = 100; - spin_unlock(&next_tag_value_lock); - new_op->upcall.type = type; - new_op->attempts = 0; - gossip_debug(GOSSIP_CACHE_DEBUG, - "Alloced OP (%p: %llu %s)\n", - new_op, - llu(new_op->tag), - get_opname_string(new_op)); - - new_op->upcall.uid = from_kuid(current_user_ns(), - current_fsuid()); - - new_op->upcall.gid = from_kgid(current_user_ns(), - current_fsgid()); - } else { - gossip_err("op_alloc: kmem_cache_alloc failed!\n"); - } - return new_op; -} - -void op_release(struct orangefs_kernel_op_s *orangefs_op) -{ - if (orangefs_op) { - gossip_debug(GOSSIP_CACHE_DEBUG, - "Releasing OP (%p: %llu)\n", - orangefs_op, - llu(orangefs_op->tag)); - orangefs_op_initialize(orangefs_op); - kmem_cache_free(op_cache, orangefs_op); - } else { - gossip_err("NULL pointer in op_release\n"); - } -} - -int dev_req_cache_initialize(void) -{ - dev_req_cache = kmem_cache_create("orangefs_devreqcache", - MAX_ALIGNED_DEV_REQ_DOWNSIZE, - 0, - ORANGEFS_CACHE_CREATE_FLAGS, - NULL); - - if (!dev_req_cache) { - gossip_err("Cannot create orangefs_dev_req_cache\n"); - return -ENOMEM; - } - return 0; -} - -int dev_req_cache_finalize(void) -{ - kmem_cache_destroy(dev_req_cache); - return 0; -} - -void *dev_req_alloc(void) -{ - void *buffer; - - buffer = kmem_cache_alloc(dev_req_cache, ORANGEFS_CACHE_ALLOC_FLAGS); - if (buffer == NULL) - gossip_err("Failed to allocate from dev_req_cache\n"); - else - memset(buffer, 0, sizeof(MAX_ALIGNED_DEV_REQ_DOWNSIZE)); - return buffer; -} - -void dev_req_release(void *buffer) -{ - if (buffer) - kmem_cache_free(dev_req_cache, buffer); - else - gossip_err("NULL pointer passed to dev_req_release\n"); -} - -int kiocb_cache_initialize(void) -{ - orangefs_kiocb_cache = kmem_cache_create("orangefs_kiocbcache", - sizeof(struct orangefs_kiocb_s), - 0, - ORANGEFS_CACHE_CREATE_FLAGS, - NULL); - - if (!orangefs_kiocb_cache) { - gossip_err("Cannot create orangefs_kiocb_cache!\n"); - return -ENOMEM; - } - return 0; -} - -int kiocb_cache_finalize(void) -{ - kmem_cache_destroy(orangefs_kiocb_cache); - return 0; -} - -struct orangefs_kiocb_s *kiocb_alloc(void) -{ - struct orangefs_kiocb_s *x = NULL; - - x = kmem_cache_alloc(orangefs_kiocb_cache, ORANGEFS_CACHE_ALLOC_FLAGS); - if (x == NULL) - gossip_err("kiocb_alloc: kmem_cache_alloc failed!\n"); - else - memset(x, 0, sizeof(struct orangefs_kiocb_s)); - return x; -} - -void kiocb_release(struct orangefs_kiocb_s *x) -{ - if (x) - kmem_cache_free(orangefs_kiocb_cache, x); - else - gossip_err("kiocb_release: kmem_cache_free NULL pointer!\n"); -} diff --git a/fs/orangefs/pvfs2-debug.h b/fs/orangefs/pvfs2-debug.h deleted file mode 100644 index e6b4baa5e8fb..000000000000 --- a/fs/orangefs/pvfs2-debug.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ - -/* This file just defines debugging masks to be used with the gossip - * logging utility. All debugging masks for ORANGEFS are kept here to make - * sure we don't have collisions. - */ - -#ifndef __ORANGEFS_DEBUG_H -#define __ORANGEFS_DEBUG_H - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#define GOSSIP_NO_DEBUG (__u64)0 -#define GOSSIP_BMI_DEBUG_TCP ((__u64)1 << 0) -#define GOSSIP_BMI_DEBUG_CONTROL ((__u64)1 << 1) -#define GOSSIP_BMI_DEBUG_OFFSETS ((__u64)1 << 2) -#define GOSSIP_BMI_DEBUG_GM ((__u64)1 << 3) -#define GOSSIP_JOB_DEBUG ((__u64)1 << 4) -#define GOSSIP_SERVER_DEBUG ((__u64)1 << 5) -#define GOSSIP_STO_DEBUG_CTRL ((__u64)1 << 6) -#define GOSSIP_STO_DEBUG_DEFAULT ((__u64)1 << 7) -#define GOSSIP_FLOW_DEBUG ((__u64)1 << 8) -#define GOSSIP_BMI_DEBUG_GM_MEM ((__u64)1 << 9) -#define GOSSIP_REQUEST_DEBUG ((__u64)1 << 10) -#define GOSSIP_FLOW_PROTO_DEBUG ((__u64)1 << 11) -#define GOSSIP_NCACHE_DEBUG ((__u64)1 << 12) -#define GOSSIP_CLIENT_DEBUG ((__u64)1 << 13) -#define GOSSIP_REQ_SCHED_DEBUG ((__u64)1 << 14) -#define GOSSIP_ACACHE_DEBUG ((__u64)1 << 15) -#define GOSSIP_TROVE_DEBUG ((__u64)1 << 16) -#define GOSSIP_TROVE_OP_DEBUG ((__u64)1 << 17) -#define GOSSIP_DIST_DEBUG ((__u64)1 << 18) -#define GOSSIP_BMI_DEBUG_IB ((__u64)1 << 19) -#define GOSSIP_DBPF_ATTRCACHE_DEBUG ((__u64)1 << 20) -#define GOSSIP_MMAP_RCACHE_DEBUG ((__u64)1 << 21) -#define GOSSIP_LOOKUP_DEBUG ((__u64)1 << 22) -#define GOSSIP_REMOVE_DEBUG ((__u64)1 << 23) -#define GOSSIP_GETATTR_DEBUG ((__u64)1 << 24) -#define GOSSIP_READDIR_DEBUG ((__u64)1 << 25) -#define GOSSIP_IO_DEBUG ((__u64)1 << 26) -#define GOSSIP_DBPF_OPEN_CACHE_DEBUG ((__u64)1 << 27) -#define GOSSIP_PERMISSIONS_DEBUG ((__u64)1 << 28) -#define GOSSIP_CANCEL_DEBUG ((__u64)1 << 29) -#define GOSSIP_MSGPAIR_DEBUG ((__u64)1 << 30) -#define GOSSIP_CLIENTCORE_DEBUG ((__u64)1 << 31) -#define GOSSIP_CLIENTCORE_TIMING_DEBUG ((__u64)1 << 32) -#define GOSSIP_SETATTR_DEBUG ((__u64)1 << 33) -#define GOSSIP_MKDIR_DEBUG ((__u64)1 << 34) -#define GOSSIP_VARSTRIP_DEBUG ((__u64)1 << 35) -#define GOSSIP_GETEATTR_DEBUG ((__u64)1 << 36) -#define GOSSIP_SETEATTR_DEBUG ((__u64)1 << 37) -#define GOSSIP_ENDECODE_DEBUG ((__u64)1 << 38) -#define GOSSIP_DELEATTR_DEBUG ((__u64)1 << 39) -#define GOSSIP_ACCESS_DEBUG ((__u64)1 << 40) -#define GOSSIP_ACCESS_DETAIL_DEBUG ((__u64)1 << 41) -#define GOSSIP_LISTEATTR_DEBUG ((__u64)1 << 42) -#define GOSSIP_PERFCOUNTER_DEBUG ((__u64)1 << 43) -#define GOSSIP_STATE_MACHINE_DEBUG ((__u64)1 << 44) -#define GOSSIP_DBPF_KEYVAL_DEBUG ((__u64)1 << 45) -#define GOSSIP_LISTATTR_DEBUG ((__u64)1 << 46) -#define GOSSIP_DBPF_COALESCE_DEBUG ((__u64)1 << 47) -#define GOSSIP_ACCESS_HOSTNAMES ((__u64)1 << 48) -#define GOSSIP_FSCK_DEBUG ((__u64)1 << 49) -#define GOSSIP_BMI_DEBUG_MX ((__u64)1 << 50) -#define GOSSIP_BSTREAM_DEBUG ((__u64)1 << 51) -#define GOSSIP_BMI_DEBUG_PORTALS ((__u64)1 << 52) -#define GOSSIP_USER_DEV_DEBUG ((__u64)1 << 53) -#define GOSSIP_DIRECTIO_DEBUG ((__u64)1 << 54) -#define GOSSIP_MGMT_DEBUG ((__u64)1 << 55) -#define GOSSIP_MIRROR_DEBUG ((__u64)1 << 56) -#define GOSSIP_WIN_CLIENT_DEBUG ((__u64)1 << 57) -#define GOSSIP_SECURITY_DEBUG ((__u64)1 << 58) -#define GOSSIP_USRINT_DEBUG ((__u64)1 << 59) -#define GOSSIP_RCACHE_DEBUG ((__u64)1 << 60) -#define GOSSIP_SECCACHE_DEBUG ((__u64)1 << 61) - -#define GOSSIP_BMI_DEBUG_ALL ((__u64) (GOSSIP_BMI_DEBUG_TCP + \ - GOSSIP_BMI_DEBUG_CONTROL + \ - GOSSIP_BMI_DEBUG_GM + \ - GOSSIP_BMI_DEBUG_OFFSETS + \ - GOSSIP_BMI_DEBUG_IB + \ - GOSSIP_BMI_DEBUG_MX + \ - GOSSIP_BMI_DEBUG_PORTALS)) - -const char *ORANGEFS_debug_get_next_debug_keyword(int position); - -#define GOSSIP_SUPER_DEBUG ((__u64)1 << 0) -#define GOSSIP_INODE_DEBUG ((__u64)1 << 1) -#define GOSSIP_FILE_DEBUG ((__u64)1 << 2) -#define GOSSIP_DIR_DEBUG ((__u64)1 << 3) -#define GOSSIP_UTILS_DEBUG ((__u64)1 << 4) -#define GOSSIP_WAIT_DEBUG ((__u64)1 << 5) -#define GOSSIP_ACL_DEBUG ((__u64)1 << 6) -#define GOSSIP_DCACHE_DEBUG ((__u64)1 << 7) -#define GOSSIP_DEV_DEBUG ((__u64)1 << 8) -#define GOSSIP_NAME_DEBUG ((__u64)1 << 9) -#define GOSSIP_BUFMAP_DEBUG ((__u64)1 << 10) -#define GOSSIP_CACHE_DEBUG ((__u64)1 << 11) -#define GOSSIP_DEBUGFS_DEBUG ((__u64)1 << 12) -#define GOSSIP_XATTR_DEBUG ((__u64)1 << 13) -#define GOSSIP_INIT_DEBUG ((__u64)1 << 14) -#define GOSSIP_SYSFS_DEBUG ((__u64)1 << 15) - -#define GOSSIP_MAX_NR 16 -#define GOSSIP_MAX_DEBUG (((__u64)1 << GOSSIP_MAX_NR) - 1) - -/*function prototypes*/ -__u64 ORANGEFS_kmod_eventlog_to_mask(const char *event_logging); -__u64 ORANGEFS_debug_eventlog_to_mask(const char *event_logging); -char *ORANGEFS_debug_mask_to_eventlog(__u64 mask); -char *ORANGEFS_kmod_mask_to_eventlog(__u64 mask); - -/* a private internal type */ -struct __keyword_mask_s { - const char *keyword; - __u64 mask_val; -}; - -#define __DEBUG_ALL ((__u64) -1) - -/* map all config keywords to pvfs2 debug masks here */ -static struct __keyword_mask_s s_keyword_mask_map[] = { - /* Log trove debugging info. Same as 'trove'. */ - {"storage", GOSSIP_TROVE_DEBUG}, - /* Log trove debugging info. Same as 'storage'. */ - {"trove", GOSSIP_TROVE_DEBUG}, - /* Log trove operations. */ - {"trove_op", GOSSIP_TROVE_OP_DEBUG}, - /* Log network debug info. */ - {"network", GOSSIP_BMI_DEBUG_ALL}, - /* Log server info, including new operations. */ - {"server", GOSSIP_SERVER_DEBUG}, - /* Log client sysint info. This is only useful for the client. */ - {"client", GOSSIP_CLIENT_DEBUG}, - /* Debug the varstrip distribution */ - {"varstrip", GOSSIP_VARSTRIP_DEBUG}, - /* Log job info */ - {"job", GOSSIP_JOB_DEBUG}, - /* Debug PINT_process_request calls. EXTREMELY verbose! */ - {"request", GOSSIP_REQUEST_DEBUG}, - /* Log request scheduler events */ - {"reqsched", GOSSIP_REQ_SCHED_DEBUG}, - /* Log the flow protocol events, including flowproto_multiqueue */ - {"flowproto", GOSSIP_FLOW_PROTO_DEBUG}, - /* Log flow calls */ - {"flow", GOSSIP_FLOW_DEBUG}, - /* Debug the client name cache. Only useful on the client. */ - {"ncache", GOSSIP_NCACHE_DEBUG}, - /* Debug read-ahead cache events. Only useful on the client. */ - {"mmaprcache", GOSSIP_MMAP_RCACHE_DEBUG}, - /* Debug the attribute cache. Only useful on the client. */ - {"acache", GOSSIP_ACACHE_DEBUG}, - /* Log/Debug distribution calls */ - {"distribution", GOSSIP_DIST_DEBUG}, - /* Debug the server-side dbpf attribute cache */ - {"dbpfattrcache", GOSSIP_DBPF_ATTRCACHE_DEBUG}, - /* Debug the client lookup state machine. */ - {"lookup", GOSSIP_LOOKUP_DEBUG}, - /* Debug the client remove state macine. */ - {"remove", GOSSIP_REMOVE_DEBUG}, - /* Debug the server getattr state machine. */ - {"getattr", GOSSIP_GETATTR_DEBUG}, - /* Debug the server setattr state machine. */ - {"setattr", GOSSIP_SETATTR_DEBUG}, - /* vectored getattr server state machine */ - {"listattr", GOSSIP_LISTATTR_DEBUG}, - /* Debug the client and server get ext attributes SM. */ - {"geteattr", GOSSIP_GETEATTR_DEBUG}, - /* Debug the client and server set ext attributes SM. */ - {"seteattr", GOSSIP_SETEATTR_DEBUG}, - /* Debug the readdir operation (client and server) */ - {"readdir", GOSSIP_READDIR_DEBUG}, - /* Debug the mkdir operation (server only) */ - {"mkdir", GOSSIP_MKDIR_DEBUG}, - /* - * Debug the io operation (reads and writes) - * for both the client and server. - */ - {"io", GOSSIP_IO_DEBUG}, - /* Debug the server's open file descriptor cache */ - {"open_cache", GOSSIP_DBPF_OPEN_CACHE_DEBUG}, - /* Debug permissions checking on the server */ - {"permissions", GOSSIP_PERMISSIONS_DEBUG}, - /* Debug the cancel operation */ - {"cancel", GOSSIP_CANCEL_DEBUG}, - /* Debug the msgpair state machine */ - {"msgpair", GOSSIP_MSGPAIR_DEBUG}, - /* Debug the client core app */ - {"clientcore", GOSSIP_CLIENTCORE_DEBUG}, - /* Debug the client timing state machines (job timeout, etc.) */ - {"clientcore_timing", GOSSIP_CLIENTCORE_TIMING_DEBUG}, - /* network encoding */ - {"endecode", GOSSIP_ENDECODE_DEBUG}, - /* Show server file (metadata) accesses (both modify and read-only). */ - {"access", GOSSIP_ACCESS_DEBUG}, - /* Show more detailed server file accesses */ - {"access_detail", GOSSIP_ACCESS_DETAIL_DEBUG}, - /* Debug the listeattr operation */ - {"listeattr", GOSSIP_LISTEATTR_DEBUG}, - /* Debug the state machine management code */ - {"sm", GOSSIP_STATE_MACHINE_DEBUG}, - /* Debug the metadata dbpf keyval functions */ - {"keyval", GOSSIP_DBPF_KEYVAL_DEBUG}, - /* Debug the metadata sync coalescing code */ - {"coalesce", GOSSIP_DBPF_COALESCE_DEBUG}, - /* Display the hostnames instead of IP addrs in debug output */ - {"access_hostnames", GOSSIP_ACCESS_HOSTNAMES}, - /* Show the client device events */ - {"user_dev", GOSSIP_USER_DEV_DEBUG}, - /* Debug the fsck tool */ - {"fsck", GOSSIP_FSCK_DEBUG}, - /* Debug the bstream code */ - {"bstream", GOSSIP_BSTREAM_DEBUG}, - /* Debug trove in direct io mode */ - {"directio", GOSSIP_DIRECTIO_DEBUG}, - /* Debug direct io thread management */ - {"mgmt", GOSSIP_MGMT_DEBUG}, - /* Debug mirroring process */ - {"mirror", GOSSIP_MIRROR_DEBUG}, - /* Windows client */ - {"win_client", GOSSIP_WIN_CLIENT_DEBUG}, - /* Debug robust security code */ - {"security", GOSSIP_SECURITY_DEBUG}, - /* Capability Cache */ - {"seccache", GOSSIP_SECCACHE_DEBUG}, - /* Client User Interface */ - {"usrint", GOSSIP_USRINT_DEBUG}, - /* rcache */ - {"rcache", GOSSIP_RCACHE_DEBUG}, - /* Everything except the periodic events. Useful for debugging */ - {"verbose", - (__DEBUG_ALL & - ~(GOSSIP_PERFCOUNTER_DEBUG | GOSSIP_STATE_MACHINE_DEBUG | - GOSSIP_ENDECODE_DEBUG | GOSSIP_USER_DEV_DEBUG)) - }, - /* No debug output */ - {"none", GOSSIP_NO_DEBUG}, - /* Everything */ - {"all", __DEBUG_ALL} -}; - -#undef __DEBUG_ALL - -/* - * Map all kmod keywords to kmod debug masks here. Keep this - * structure "packed": - * - * "all" is always last... - * - * keyword mask_val index - * foo 1 0 - * bar 2 1 - * baz 4 2 - * qux 8 3 - * . . . - */ -static struct __keyword_mask_s s_kmod_keyword_mask_map[] = { - {"super", GOSSIP_SUPER_DEBUG}, - {"inode", GOSSIP_INODE_DEBUG}, - {"file", GOSSIP_FILE_DEBUG}, - {"dir", GOSSIP_DIR_DEBUG}, - {"utils", GOSSIP_UTILS_DEBUG}, - {"wait", GOSSIP_WAIT_DEBUG}, - {"acl", GOSSIP_ACL_DEBUG}, - {"dcache", GOSSIP_DCACHE_DEBUG}, - {"dev", GOSSIP_DEV_DEBUG}, - {"name", GOSSIP_NAME_DEBUG}, - {"bufmap", GOSSIP_BUFMAP_DEBUG}, - {"cache", GOSSIP_CACHE_DEBUG}, - {"debugfs", GOSSIP_DEBUGFS_DEBUG}, - {"xattr", GOSSIP_XATTR_DEBUG}, - {"init", GOSSIP_INIT_DEBUG}, - {"sysfs", GOSSIP_SYSFS_DEBUG}, - {"none", GOSSIP_NO_DEBUG}, - {"all", GOSSIP_MAX_DEBUG} -}; - -static const int num_kmod_keyword_mask_map = (int) - (sizeof(s_kmod_keyword_mask_map) / sizeof(struct __keyword_mask_s)); - -static const int num_keyword_mask_map = (int) - (sizeof(s_keyword_mask_map) / sizeof(struct __keyword_mask_s)); - -#endif /* __ORANGEFS_DEBUG_H */ diff --git a/fs/orangefs/pvfs2-debugfs.c b/fs/orangefs/pvfs2-debugfs.c deleted file mode 100644 index 315dc538b723..000000000000 --- a/fs/orangefs/pvfs2-debugfs.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * What: /sys/kernel/debug/orangefs/debug-help - * Date: June 2015 - * Contact: Mike Marshall - * Description: - * List of client and kernel debug keywords. - * - * - * What: /sys/kernel/debug/orangefs/client-debug - * Date: June 2015 - * Contact: Mike Marshall - * Description: - * Debug setting for "the client", the userspace - * helper for the kernel module. - * - * - * What: /sys/kernel/debug/orangefs/kernel-debug - * Date: June 2015 - * Contact: Mike Marshall - * Description: - * Debug setting for the orangefs kernel module. - * - * Any of the keywords, or comma-separated lists - * of keywords, from debug-help can be catted to - * client-debug or kernel-debug. - * - * "none", "all" and "verbose" are special keywords - * for client-debug. Setting client-debug to "all" - * is kind of like trying to drink water from a - * fire hose, "verbose" triggers most of the same - * output except for the constant flow of output - * from the main wait loop. - * - * "none" and "all" are similar settings for kernel-debug - * no need for a "verbose". - */ -#include -#include - -#include - -#include "pvfs2-debugfs.h" -#include "protocol.h" -#include "pvfs2-kernel.h" - -static int orangefs_debug_disabled = 1; - -static int orangefs_debug_help_open(struct inode *, struct file *); - -const struct file_operations debug_help_fops = { - .open = orangefs_debug_help_open, - .read = seq_read, - .release = seq_release, - .llseek = seq_lseek, -}; - -static void *help_start(struct seq_file *, loff_t *); -static void *help_next(struct seq_file *, void *, loff_t *); -static void help_stop(struct seq_file *, void *); -static int help_show(struct seq_file *, void *); - -static const struct seq_operations help_debug_ops = { - .start = help_start, - .next = help_next, - .stop = help_stop, - .show = help_show, -}; - -/* - * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and - * ORANGEFS_KMOD_DEBUG_FILE. - */ -static DEFINE_MUTEX(orangefs_debug_lock); - -int orangefs_debug_open(struct inode *, struct file *); - -static ssize_t orangefs_debug_read(struct file *, - char __user *, - size_t, - loff_t *); - -static ssize_t orangefs_debug_write(struct file *, - const char __user *, - size_t, - loff_t *); - -static const struct file_operations kernel_debug_fops = { - .open = orangefs_debug_open, - .read = orangefs_debug_read, - .write = orangefs_debug_write, - .llseek = generic_file_llseek, -}; - -/* - * initialize kmod debug operations, create orangefs debugfs dir and - * ORANGEFS_KMOD_DEBUG_HELP_FILE. - */ -int orangefs_debugfs_init(void) -{ - - int rc = -ENOMEM; - - debug_dir = debugfs_create_dir("orangefs", NULL); - if (!debug_dir) - goto out; - - help_file_dentry = debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE, - 0444, - debug_dir, - debug_help_string, - &debug_help_fops); - if (!help_file_dentry) - goto out; - - orangefs_debug_disabled = 0; - rc = 0; - -out: - if (rc) - orangefs_debugfs_cleanup(); - - return rc; -} - -void orangefs_debugfs_cleanup(void) -{ - debugfs_remove_recursive(debug_dir); -} - -/* open ORANGEFS_KMOD_DEBUG_HELP_FILE */ -static int orangefs_debug_help_open(struct inode *inode, struct file *file) -{ - int rc = -ENODEV; - int ret; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "orangefs_debug_help_open: start\n"); - - if (orangefs_debug_disabled) - goto out; - - ret = seq_open(file, &help_debug_ops); - if (ret) - goto out; - - ((struct seq_file *)(file->private_data))->private = inode->i_private; - - rc = 0; - -out: - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "orangefs_debug_help_open: rc:%d:\n", - rc); - return rc; -} - -/* - * I think start always gets called again after stop. Start - * needs to return NULL when it is done. The whole "payload" - * in this case is a single (long) string, so by the second - * time we get to start (pos = 1), we're done. - */ -static void *help_start(struct seq_file *m, loff_t *pos) -{ - void *payload = NULL; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n"); - - if (*pos == 0) - payload = m->private; - - return payload; -} - -static void *help_next(struct seq_file *m, void *v, loff_t *pos) -{ - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n"); - - return NULL; -} - -static void help_stop(struct seq_file *m, void *p) -{ - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n"); -} - -static int help_show(struct seq_file *m, void *v) -{ - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n"); - - seq_puts(m, v); - - return 0; -} - -/* - * initialize the kernel-debug file. - */ -int orangefs_kernel_debug_init(void) -{ - - int rc = -ENOMEM; - struct dentry *ret; - char *k_buffer = NULL; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__); - - k_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); - if (!k_buffer) - goto out; - - if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) { - strcpy(k_buffer, kernel_debug_string); - strcat(k_buffer, "\n"); - } else { - strcpy(k_buffer, "none\n"); - pr_info("%s: overflow 1!\n", __func__); - } - - ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE, - 0444, - debug_dir, - k_buffer, - &kernel_debug_fops); - if (!ret) { - pr_info("%s: failed to create %s.\n", - __func__, - ORANGEFS_KMOD_DEBUG_FILE); - goto out; - } - - rc = 0; - -out: - if (rc) - orangefs_debugfs_cleanup(); - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc); - return rc; -} - -/* - * initialize the client-debug file. - */ -int orangefs_client_debug_init(void) -{ - - int rc = -ENOMEM; - char *c_buffer = NULL; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__); - - c_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); - if (!c_buffer) - goto out; - - if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) { - strcpy(c_buffer, client_debug_string); - strcat(c_buffer, "\n"); - } else { - strcpy(c_buffer, "none\n"); - pr_info("%s: overflow! 2\n", __func__); - } - - client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE, - 0444, - debug_dir, - c_buffer, - &kernel_debug_fops); - if (!client_debug_dentry) { - pr_info("%s: failed to create %s.\n", - __func__, - ORANGEFS_CLIENT_DEBUG_FILE); - goto out; - } - - rc = 0; - -out: - if (rc) - orangefs_debugfs_cleanup(); - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc); - return rc; -} - -/* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/ -int orangefs_debug_open(struct inode *inode, struct file *file) -{ - int rc = -ENODEV; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "%s: orangefs_debug_disabled: %d\n", - __func__, - orangefs_debug_disabled); - - if (orangefs_debug_disabled) - goto out; - - rc = 0; - mutex_lock(&orangefs_debug_lock); - file->private_data = inode->i_private; - mutex_unlock(&orangefs_debug_lock); - -out: - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "orangefs_debug_open: rc: %d\n", - rc); - return rc; -} - -static ssize_t orangefs_debug_read(struct file *file, - char __user *ubuf, - size_t count, - loff_t *ppos) -{ - char *buf; - int sprintf_ret; - ssize_t read_ret = -ENOMEM; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n"); - - buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); - if (!buf) - goto out; - - mutex_lock(&orangefs_debug_lock); - sprintf_ret = sprintf(buf, "%s", (char *)file->private_data); - mutex_unlock(&orangefs_debug_lock); - - read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret); - - kfree(buf); - -out: - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "orangefs_debug_read: ret: %zu\n", - read_ret); - - return read_ret; -} - -static ssize_t orangefs_debug_write(struct file *file, - const char __user *ubuf, - size_t count, - loff_t *ppos) -{ - char *buf; - int rc = -EFAULT; - size_t silly = 0; - char *debug_string; - struct orangefs_kernel_op_s *new_op = NULL; - struct client_debug_mask c_mask = { NULL, 0, 0 }; - - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "orangefs_debug_write: %s\n", - file->f_path.dentry->d_name.name); - - /* - * Thwart users who try to jamb a ridiculous number - * of bytes into the debug file... - */ - if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) { - silly = count; - count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1; - } - - buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); - if (!buf) - goto out; - memset(buf, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); - - if (copy_from_user(buf, ubuf, count - 1)) { - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "%s: copy_from_user failed!\n", - __func__); - goto out; - } - - /* - * Map the keyword string from userspace into a valid debug mask. - * The mapping process involves mapping the human-inputted string - * into a valid mask, and then rebuilding the string from the - * verified valid mask. - * - * A service operation is required to set a new client-side - * debug mask. - */ - if (!strcmp(file->f_path.dentry->d_name.name, - ORANGEFS_KMOD_DEBUG_FILE)) { - debug_string_to_mask(buf, &gossip_debug_mask, 0); - debug_mask_to_string(&gossip_debug_mask, 0); - debug_string = kernel_debug_string; - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "New kernel debug string is %s\n", - kernel_debug_string); - } else { - /* Can't reset client debug mask if client is not running. */ - if (is_daemon_in_service()) { - pr_info("%s: Client not running :%d:\n", - __func__, - is_daemon_in_service()); - goto out; - } - - debug_string_to_mask(buf, &c_mask, 1); - debug_mask_to_string(&c_mask, 1); - debug_string = client_debug_string; - - new_op = op_alloc(ORANGEFS_VFS_OP_PARAM); - if (!new_op) { - pr_info("%s: op_alloc failed!\n", __func__); - goto out; - } - - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES; - new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET; - memset(new_op->upcall.req.param.s_value, - 0, - ORANGEFS_MAX_DEBUG_STRING_LEN); - sprintf(new_op->upcall.req.param.s_value, - "%llx %llx\n", - c_mask.mask1, - c_mask.mask2); - - /* service_operation returns 0 on success... */ - rc = service_operation(new_op, - "orangefs_param", - ORANGEFS_OP_INTERRUPTIBLE); - - if (rc) - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "%s: service_operation failed! rc:%d:\n", - __func__, - rc); - - op_release(new_op); - } - - mutex_lock(&orangefs_debug_lock); - memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); - sprintf((char *)file->f_inode->i_private, "%s\n", debug_string); - mutex_unlock(&orangefs_debug_lock); - - *ppos += count; - if (silly) - rc = silly; - else - rc = count; - -out: - gossip_debug(GOSSIP_DEBUGFS_DEBUG, - "orangefs_debug_write: rc: %d\n", - rc); - kfree(buf); - return rc; -} diff --git a/fs/orangefs/pvfs2-debugfs.h b/fs/orangefs/pvfs2-debugfs.h deleted file mode 100644 index e4828c0e3ef9..000000000000 --- a/fs/orangefs/pvfs2-debugfs.h +++ /dev/null @@ -1,3 +0,0 @@ -int orangefs_debugfs_init(void); -int orangefs_kernel_debug_init(void); -void orangefs_debugfs_cleanup(void); diff --git a/fs/orangefs/pvfs2-dev-proto.h b/fs/orangefs/pvfs2-dev-proto.h deleted file mode 100644 index dc1951dd7045..000000000000 --- a/fs/orangefs/pvfs2-dev-proto.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ - -#ifndef _ORANGEFS_DEV_PROTO_H -#define _ORANGEFS_DEV_PROTO_H - -/* - * types and constants shared between user space and kernel space for - * device interaction using a common protocol - */ - -/* - * valid orangefs kernel operation types - */ -#define ORANGEFS_VFS_OP_INVALID 0xFF000000 -#define ORANGEFS_VFS_OP_FILE_IO 0xFF000001 -#define ORANGEFS_VFS_OP_LOOKUP 0xFF000002 -#define ORANGEFS_VFS_OP_CREATE 0xFF000003 -#define ORANGEFS_VFS_OP_GETATTR 0xFF000004 -#define ORANGEFS_VFS_OP_REMOVE 0xFF000005 -#define ORANGEFS_VFS_OP_MKDIR 0xFF000006 -#define ORANGEFS_VFS_OP_READDIR 0xFF000007 -#define ORANGEFS_VFS_OP_SETATTR 0xFF000008 -#define ORANGEFS_VFS_OP_SYMLINK 0xFF000009 -#define ORANGEFS_VFS_OP_RENAME 0xFF00000A -#define ORANGEFS_VFS_OP_STATFS 0xFF00000B -#define ORANGEFS_VFS_OP_TRUNCATE 0xFF00000C -#define ORANGEFS_VFS_OP_MMAP_RA_FLUSH 0xFF00000D -#define ORANGEFS_VFS_OP_FS_MOUNT 0xFF00000E -#define ORANGEFS_VFS_OP_FS_UMOUNT 0xFF00000F -#define ORANGEFS_VFS_OP_GETXATTR 0xFF000010 -#define ORANGEFS_VFS_OP_SETXATTR 0xFF000011 -#define ORANGEFS_VFS_OP_LISTXATTR 0xFF000012 -#define ORANGEFS_VFS_OP_REMOVEXATTR 0xFF000013 -#define ORANGEFS_VFS_OP_PARAM 0xFF000014 -#define ORANGEFS_VFS_OP_PERF_COUNT 0xFF000015 -#define ORANGEFS_VFS_OP_CANCEL 0xFF00EE00 -#define ORANGEFS_VFS_OP_FSYNC 0xFF00EE01 -#define ORANGEFS_VFS_OP_FSKEY 0xFF00EE02 -#define ORANGEFS_VFS_OP_READDIRPLUS 0xFF00EE03 - -/* - * Misc constants. Please retain them as multiples of 8! - * Otherwise 32-64 bit interactions will be messed up :) - */ -#define ORANGEFS_NAME_LEN 0x00000100 -#define ORANGEFS_MAX_DEBUG_STRING_LEN 0x00000400 -#define ORANGEFS_MAX_DEBUG_ARRAY_LEN 0x00000800 - -/* - * MAX_DIRENT_COUNT cannot be larger than ORANGEFS_REQ_LIMIT_LISTATTR. - * The value of ORANGEFS_REQ_LIMIT_LISTATTR has been changed from 113 to 60 - * to accomodate an attribute object with mirrored handles. - * MAX_DIRENT_COUNT is replaced by MAX_DIRENT_COUNT_READDIR and - * MAX_DIRENT_COUNT_READDIRPLUS, since readdir doesn't trigger a listattr - * but readdirplus might. -*/ -#define MAX_DIRENT_COUNT_READDIR 0x00000060 -#define MAX_DIRENT_COUNT_READDIRPLUS 0x0000003C - -#include "upcall.h" -#include "downcall.h" - -/* - * These macros differ from proto macros in that they don't do any - * byte-swappings and are used to ensure that kernel-clientcore interactions - * don't cause any unaligned accesses etc on 64 bit machines - */ -#ifndef roundup4 -#define roundup4(x) (((x)+3) & ~3) -#endif - -#ifndef roundup8 -#define roundup8(x) (((x)+7) & ~7) -#endif - -struct read_write_x { - __s64 off; - __s64 len; -}; - -#endif diff --git a/fs/orangefs/pvfs2-kernel.h b/fs/orangefs/pvfs2-kernel.h deleted file mode 100644 index 33fcf3bccd2e..000000000000 --- a/fs/orangefs/pvfs2-kernel.h +++ /dev/null @@ -1,819 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ - -/* - * The ORANGEFS Linux kernel support allows ORANGEFS volumes to be mounted and - * accessed through the Linux VFS (i.e. using standard I/O system calls). - * This support is only needed on clients that wish to mount the file system. - * - */ - -/* - * Declarations and macros for the ORANGEFS Linux kernel support. - */ - -#ifndef __ORANGEFSKERNEL_H -#define __ORANGEFSKERNEL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "pvfs2-dev-proto.h" - -#ifdef ORANGEFS_KERNEL_DEBUG -#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS 10 -#else -#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS 20 -#endif - -#define ORANGEFS_BUFMAP_WAIT_TIMEOUT_SECS 30 - -#define ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS 900 /* 15 minutes */ - -#define ORANGEFS_REQDEVICE_NAME "pvfs2-req" - -#define ORANGEFS_DEVREQ_MAGIC 0x20030529 -#define ORANGEFS_LINK_MAX 0x000000FF -#define ORANGEFS_PURGE_RETRY_COUNT 0x00000005 -#define ORANGEFS_SEEK_END 0x00000002 -#define ORANGEFS_MAX_NUM_OPTIONS 0x00000004 -#define ORANGEFS_MAX_MOUNT_OPT_LEN 0x00000080 -#define ORANGEFS_MAX_FSKEY_LEN 64 - -#define MAX_DEV_REQ_UPSIZE (2*sizeof(__s32) + \ -sizeof(__u64) + sizeof(struct orangefs_upcall_s)) -#define MAX_DEV_REQ_DOWNSIZE (2*sizeof(__s32) + \ -sizeof(__u64) + sizeof(struct orangefs_downcall_s)) - -#define BITS_PER_LONG_DIV_8 (BITS_PER_LONG >> 3) - -/* borrowed from irda.h */ -#ifndef MSECS_TO_JIFFIES -#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000) -#endif - -#define MAX_ALIGNED_DEV_REQ_UPSIZE \ - (MAX_DEV_REQ_UPSIZE + \ - ((((MAX_DEV_REQ_UPSIZE / \ - (BITS_PER_LONG_DIV_8)) * \ - (BITS_PER_LONG_DIV_8)) + \ - (BITS_PER_LONG_DIV_8)) - \ - MAX_DEV_REQ_UPSIZE)) - -#define MAX_ALIGNED_DEV_REQ_DOWNSIZE \ - (MAX_DEV_REQ_DOWNSIZE + \ - ((((MAX_DEV_REQ_DOWNSIZE / \ - (BITS_PER_LONG_DIV_8)) * \ - (BITS_PER_LONG_DIV_8)) + \ - (BITS_PER_LONG_DIV_8)) - \ - MAX_DEV_REQ_DOWNSIZE)) - -/* - * valid orangefs kernel operation states - * - * unknown - op was just initialized - * waiting - op is on request_list (upward bound) - * inprogr - op is in progress (waiting for downcall) - * serviced - op has matching downcall; ok - * purged - op has to start a timer since client-core - * exited uncleanly before servicing op - */ -enum orangefs_vfs_op_states { - OP_VFS_STATE_UNKNOWN = 0, - OP_VFS_STATE_WAITING = 1, - OP_VFS_STATE_INPROGR = 2, - OP_VFS_STATE_SERVICED = 4, - OP_VFS_STATE_PURGED = 8, -}; - -#define set_op_state_waiting(op) ((op)->op_state = OP_VFS_STATE_WAITING) -#define set_op_state_inprogress(op) ((op)->op_state = OP_VFS_STATE_INPROGR) -#define set_op_state_serviced(op) ((op)->op_state = OP_VFS_STATE_SERVICED) -#define set_op_state_purged(op) ((op)->op_state |= OP_VFS_STATE_PURGED) - -#define op_state_waiting(op) ((op)->op_state & OP_VFS_STATE_WAITING) -#define op_state_in_progress(op) ((op)->op_state & OP_VFS_STATE_INPROGR) -#define op_state_serviced(op) ((op)->op_state & OP_VFS_STATE_SERVICED) -#define op_state_purged(op) ((op)->op_state & OP_VFS_STATE_PURGED) - -#define get_op(op) \ - do { \ - atomic_inc(&(op)->aio_ref_count); \ - gossip_debug(GOSSIP_DEV_DEBUG, \ - "(get) Alloced OP (%p:%llu)\n", \ - op, \ - llu((op)->tag)); \ - } while (0) - -#define put_op(op) \ - do { \ - if (atomic_sub_and_test(1, &(op)->aio_ref_count) == 1) { \ - gossip_debug(GOSSIP_DEV_DEBUG, \ - "(put) Releasing OP (%p:%llu)\n", \ - op, \ - llu((op)->tag)); \ - op_release(op); \ - } \ - } while (0) - -#define op_wait(op) (atomic_read(&(op)->aio_ref_count) <= 2 ? 0 : 1) - -/* - * Defines for controlling whether I/O upcalls are for async or sync operations - */ -enum ORANGEFS_async_io_type { - ORANGEFS_VFS_SYNC_IO = 0, - ORANGEFS_VFS_ASYNC_IO = 1, -}; - -/* - * An array of client_debug_mask will be built to hold debug keyword/mask - * values fetched from userspace. - */ -struct client_debug_mask { - char *keyword; - __u64 mask1; - __u64 mask2; -}; - -/* - * orangefs kernel memory related flags - */ - -#if ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB)) -#define ORANGEFS_CACHE_CREATE_FLAGS SLAB_RED_ZONE -#else -#define ORANGEFS_CACHE_CREATE_FLAGS 0 -#endif /* ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB)) */ - -#define ORANGEFS_CACHE_ALLOC_FLAGS (GFP_KERNEL) -#define ORANGEFS_GFP_FLAGS (GFP_KERNEL) -#define ORANGEFS_BUFMAP_GFP_FLAGS (GFP_KERNEL) - -/* orangefs xattr and acl related defines */ -#define ORANGEFS_XATTR_INDEX_POSIX_ACL_ACCESS 1 -#define ORANGEFS_XATTR_INDEX_POSIX_ACL_DEFAULT 2 -#define ORANGEFS_XATTR_INDEX_TRUSTED 3 -#define ORANGEFS_XATTR_INDEX_DEFAULT 4 - -#if 0 -#ifndef POSIX_ACL_XATTR_ACCESS -#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" -#endif -#ifndef POSIX_ACL_XATTR_DEFAULT -#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" -#endif -#endif - -#define ORANGEFS_XATTR_NAME_ACL_ACCESS POSIX_ACL_XATTR_ACCESS -#define ORANGEFS_XATTR_NAME_ACL_DEFAULT POSIX_ACL_XATTR_DEFAULT -#define ORANGEFS_XATTR_NAME_TRUSTED_PREFIX "trusted." -#define ORANGEFS_XATTR_NAME_DEFAULT_PREFIX "" - -/* these functions are defined in orangefs-utils.c */ -int orangefs_prepare_cdm_array(char *debug_array_string); -int orangefs_prepare_debugfs_help_string(int); - -/* defined in orangefs-debugfs.c */ -int orangefs_client_debug_init(void); - -void debug_string_to_mask(char *, void *, int); -void do_c_mask(int, char *, struct client_debug_mask **); -void do_k_mask(int, char *, __u64 **); - -void debug_mask_to_string(void *, int); -void do_k_string(void *, int); -void do_c_string(void *, int); -int check_amalgam_keyword(void *, int); -int keyword_is_amalgam(char *); - -/*these variables are defined in orangefs-mod.c */ -extern char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; -extern char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; -extern char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; -extern unsigned int kernel_mask_set_mod_init; - -extern int orangefs_init_acl(struct inode *inode, struct inode *dir); -extern const struct xattr_handler *orangefs_xattr_handlers[]; - -extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type); -extern int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type); - -/* - * Redefine xtvec structure so that we could move helper functions out of - * the define - */ -struct xtvec { - __kernel_off_t xtv_off; /* must be off_t */ - __kernel_size_t xtv_len; /* must be size_t */ -}; - -/* - * orangefs data structures - */ -struct orangefs_kernel_op_s { - enum orangefs_vfs_op_states op_state; - __u64 tag; - - /* - * Set uses_shared_memory to 1 if this operation uses shared memory. - * If true, then a retry on the op must also get a new shared memory - * buffer and re-populate it. - */ - int uses_shared_memory; - - struct orangefs_upcall_s upcall; - struct orangefs_downcall_s downcall; - - wait_queue_head_t waitq; - spinlock_t lock; - - int io_completed; - wait_queue_head_t io_completion_waitq; - - /* VFS aio fields */ - - /* used by the async I/O code to stash the orangefs_kiocb_s structure */ - void *priv; - - /* used again for the async I/O code for deallocation */ - atomic_t aio_ref_count; - - int attempts; - - struct list_head list; -}; - -/* per inode private orangefs info */ -struct orangefs_inode_s { - struct orangefs_object_kref refn; - char link_target[ORANGEFS_NAME_MAX]; - __s64 blksize; - /* - * Reading/Writing Extended attributes need to acquire the appropriate - * reader/writer semaphore on the orangefs_inode_s structure. - */ - struct rw_semaphore xattr_sem; - - struct inode vfs_inode; - sector_t last_failed_block_index_read; - - /* - * State of in-memory attributes not yet flushed to disk associated - * with this object - */ - unsigned long pinode_flags; - - /* All allocated orangefs_inode_s objects are chained to a list */ - struct list_head list; -}; - -#define P_ATIME_FLAG 0 -#define P_MTIME_FLAG 1 -#define P_CTIME_FLAG 2 -#define P_MODE_FLAG 3 - -#define ClearAtimeFlag(pinode) clear_bit(P_ATIME_FLAG, &(pinode)->pinode_flags) -#define SetAtimeFlag(pinode) set_bit(P_ATIME_FLAG, &(pinode)->pinode_flags) -#define AtimeFlag(pinode) test_bit(P_ATIME_FLAG, &(pinode)->pinode_flags) - -#define ClearMtimeFlag(pinode) clear_bit(P_MTIME_FLAG, &(pinode)->pinode_flags) -#define SetMtimeFlag(pinode) set_bit(P_MTIME_FLAG, &(pinode)->pinode_flags) -#define MtimeFlag(pinode) test_bit(P_MTIME_FLAG, &(pinode)->pinode_flags) - -#define ClearCtimeFlag(pinode) clear_bit(P_CTIME_FLAG, &(pinode)->pinode_flags) -#define SetCtimeFlag(pinode) set_bit(P_CTIME_FLAG, &(pinode)->pinode_flags) -#define CtimeFlag(pinode) test_bit(P_CTIME_FLAG, &(pinode)->pinode_flags) - -#define ClearModeFlag(pinode) clear_bit(P_MODE_FLAG, &(pinode)->pinode_flags) -#define SetModeFlag(pinode) set_bit(P_MODE_FLAG, &(pinode)->pinode_flags) -#define ModeFlag(pinode) test_bit(P_MODE_FLAG, &(pinode)->pinode_flags) - -/* per superblock private orangefs info */ -struct orangefs_sb_info_s { - struct orangefs_khandle root_khandle; - __s32 fs_id; - int id; - int flags; -#define ORANGEFS_OPT_INTR 0x01 -#define ORANGEFS_OPT_LOCAL_LOCK 0x02 - char devname[ORANGEFS_MAX_SERVER_ADDR_LEN]; - struct super_block *sb; - int mount_pending; - struct list_head list; -}; - -/* - * structure that holds the state of any async I/O operation issued - * through the VFS. Needed especially to handle cancellation requests - * or even completion notification so that the VFS client-side daemon - * can free up its vfs_request slots. - */ -struct orangefs_kiocb_s { - /* the pointer to the task that initiated the AIO */ - struct task_struct *tsk; - - /* pointer to the kiocb that kicked this operation */ - struct kiocb *kiocb; - - /* buffer index that was used for the I/O */ - struct orangefs_bufmap *bufmap; - int buffer_index; - - /* orangefs kernel operation type */ - struct orangefs_kernel_op_s *op; - - /* The user space buffers from/to which I/O is being staged */ - struct iovec *iov; - - /* number of elements in the iovector */ - unsigned long nr_segs; - - /* set to indicate the type of the operation */ - int rw; - - /* file offset */ - loff_t offset; - - /* and the count in bytes */ - size_t bytes_to_be_copied; - - ssize_t bytes_copied; - int needs_cleanup; -}; - -struct orangefs_stats { - unsigned long cache_hits; - unsigned long cache_misses; - unsigned long reads; - unsigned long writes; -}; - -extern struct orangefs_stats g_orangefs_stats; - -/* - * NOTE: See Documentation/filesystems/porting for information - * on implementing FOO_I and properly accessing fs private data - */ -static inline struct orangefs_inode_s *ORANGEFS_I(struct inode *inode) -{ - return container_of(inode, struct orangefs_inode_s, vfs_inode); -} - -static inline struct orangefs_sb_info_s *ORANGEFS_SB(struct super_block *sb) -{ - return (struct orangefs_sb_info_s *) sb->s_fs_info; -} - -/* ino_t descends from "unsigned long", 8 bytes, 64 bits. */ -static inline ino_t orangefs_khandle_to_ino(struct orangefs_khandle *khandle) -{ - union { - unsigned char u[8]; - __u64 ino; - } ihandle; - - ihandle.u[0] = khandle->u[0] ^ khandle->u[4]; - ihandle.u[1] = khandle->u[1] ^ khandle->u[5]; - ihandle.u[2] = khandle->u[2] ^ khandle->u[6]; - ihandle.u[3] = khandle->u[3] ^ khandle->u[7]; - ihandle.u[4] = khandle->u[12] ^ khandle->u[8]; - ihandle.u[5] = khandle->u[13] ^ khandle->u[9]; - ihandle.u[6] = khandle->u[14] ^ khandle->u[10]; - ihandle.u[7] = khandle->u[15] ^ khandle->u[11]; - - return ihandle.ino; -} - -static inline struct orangefs_khandle *get_khandle_from_ino(struct inode *inode) -{ - return &(ORANGEFS_I(inode)->refn.khandle); -} - -static inline __s32 get_fsid_from_ino(struct inode *inode) -{ - return ORANGEFS_I(inode)->refn.fs_id; -} - -static inline ino_t get_ino_from_khandle(struct inode *inode) -{ - struct orangefs_khandle *khandle; - ino_t ino; - - khandle = get_khandle_from_ino(inode); - ino = orangefs_khandle_to_ino(khandle); - return ino; -} - -static inline ino_t get_parent_ino_from_dentry(struct dentry *dentry) -{ - return get_ino_from_khandle(dentry->d_parent->d_inode); -} - -static inline int is_root_handle(struct inode *inode) -{ - gossip_debug(GOSSIP_DCACHE_DEBUG, - "%s: root handle: %pU, this handle: %pU:\n", - __func__, - &ORANGEFS_SB(inode->i_sb)->root_khandle, - get_khandle_from_ino(inode)); - - if (ORANGEFS_khandle_cmp(&(ORANGEFS_SB(inode->i_sb)->root_khandle), - get_khandle_from_ino(inode))) - return 0; - else - return 1; -} - -static inline int match_handle(struct orangefs_khandle resp_handle, - struct inode *inode) -{ - gossip_debug(GOSSIP_DCACHE_DEBUG, - "%s: one handle: %pU, another handle:%pU:\n", - __func__, - &resp_handle, - get_khandle_from_ino(inode)); - - if (ORANGEFS_khandle_cmp(&resp_handle, get_khandle_from_ino(inode))) - return 0; - else - return 1; -} - -/* - * defined in orangefs-cache.c - */ -int op_cache_initialize(void); -int op_cache_finalize(void); -struct orangefs_kernel_op_s *op_alloc(__s32 type); -char *get_opname_string(struct orangefs_kernel_op_s *new_op); -void op_release(struct orangefs_kernel_op_s *op); - -int dev_req_cache_initialize(void); -int dev_req_cache_finalize(void); -void *dev_req_alloc(void); -void dev_req_release(void *); - -int orangefs_inode_cache_initialize(void); -int orangefs_inode_cache_finalize(void); - -int kiocb_cache_initialize(void); -int kiocb_cache_finalize(void); -struct orangefs_kiocb_s *kiocb_alloc(void); -void kiocb_release(struct orangefs_kiocb_s *ptr); - -/* - * defined in orangefs-mod.c - */ -void purge_inprogress_ops(void); - -/* - * defined in waitqueue.c - */ -int wait_for_matching_downcall(struct orangefs_kernel_op_s *op); -int wait_for_cancellation_downcall(struct orangefs_kernel_op_s *op); -void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op); -void purge_waiting_ops(void); - -/* - * defined in super.c - */ -struct dentry *orangefs_mount(struct file_system_type *fst, - int flags, - const char *devname, - void *data); - -void orangefs_kill_sb(struct super_block *sb); -int orangefs_remount(struct super_block *sb); - -int fsid_key_table_initialize(void); -void fsid_key_table_finalize(void); - -/* - * defined in inode.c - */ -__u32 convert_to_orangefs_mask(unsigned long lite_mask); -struct inode *orangefs_new_inode(struct super_block *sb, - struct inode *dir, - int mode, - dev_t dev, - struct orangefs_object_kref *ref); - -int orangefs_setattr(struct dentry *dentry, struct iattr *iattr); - -int orangefs_getattr(struct vfsmount *mnt, - struct dentry *dentry, - struct kstat *kstat); - -/* - * defined in xattr.c - */ -int orangefs_setxattr(struct dentry *dentry, - const char *name, - const void *value, - size_t size, - int flags); - -ssize_t orangefs_getxattr(struct dentry *dentry, - const char *name, - void *buffer, - size_t size); - -ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size); - -/* - * defined in namei.c - */ -struct inode *orangefs_iget(struct super_block *sb, - struct orangefs_object_kref *ref); - -ssize_t orangefs_inode_read(struct inode *inode, - struct iov_iter *iter, - loff_t *offset, - loff_t readahead_size); - -/* - * defined in devorangefs-req.c - */ -int orangefs_dev_init(void); -void orangefs_dev_cleanup(void); -int is_daemon_in_service(void); -int fs_mount_pending(__s32 fsid); - -/* - * defined in orangefs-utils.c - */ -__s32 fsid_of_op(struct orangefs_kernel_op_s *op); - -int orangefs_flush_inode(struct inode *inode); - -ssize_t orangefs_inode_getxattr(struct inode *inode, - const char *prefix, - const char *name, - void *buffer, - size_t size); - -int orangefs_inode_setxattr(struct inode *inode, - const char *prefix, - const char *name, - const void *value, - size_t size, - int flags); - -int orangefs_inode_getattr(struct inode *inode, __u32 mask); - -int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr); - -void orangefs_op_initialize(struct orangefs_kernel_op_s *op); - -void orangefs_make_bad_inode(struct inode *inode); - -void block_signals(sigset_t *); - -void set_signals(sigset_t *); - -int orangefs_unmount_sb(struct super_block *sb); - -int orangefs_cancel_op_in_progress(__u64 tag); - -static inline __u64 orangefs_convert_time_field(const struct timespec *ts) -{ - return (__u64)ts->tv_sec; -} - -int orangefs_normalize_to_errno(__s32 error_code); - -extern struct mutex devreq_mutex; -extern struct mutex request_mutex; -extern int debug; -extern int op_timeout_secs; -extern int slot_timeout_secs; -extern struct list_head orangefs_superblocks; -extern spinlock_t orangefs_superblocks_lock; -extern struct list_head orangefs_request_list; -extern spinlock_t orangefs_request_list_lock; -extern wait_queue_head_t orangefs_request_list_waitq; -extern struct list_head *htable_ops_in_progress; -extern spinlock_t htable_ops_in_progress_lock; -extern int hash_table_size; - -extern const struct address_space_operations orangefs_address_operations; -extern struct backing_dev_info orangefs_backing_dev_info; -extern struct inode_operations orangefs_file_inode_operations; -extern const struct file_operations orangefs_file_operations; -extern struct inode_operations orangefs_symlink_inode_operations; -extern struct inode_operations orangefs_dir_inode_operations; -extern const struct file_operations orangefs_dir_operations; -extern const struct dentry_operations orangefs_dentry_operations; -extern const struct file_operations orangefs_devreq_file_operations; - -extern wait_queue_head_t orangefs_bufmap_init_waitq; - -/* - * misc convenience macros - */ -#define add_op_to_request_list(op) \ -do { \ - spin_lock(&orangefs_request_list_lock); \ - spin_lock(&op->lock); \ - set_op_state_waiting(op); \ - list_add_tail(&op->list, &orangefs_request_list); \ - spin_unlock(&orangefs_request_list_lock); \ - spin_unlock(&op->lock); \ - wake_up_interruptible(&orangefs_request_list_waitq); \ -} while (0) - -#define add_priority_op_to_request_list(op) \ - do { \ - spin_lock(&orangefs_request_list_lock); \ - spin_lock(&op->lock); \ - set_op_state_waiting(op); \ - \ - list_add(&op->list, &orangefs_request_list); \ - spin_unlock(&orangefs_request_list_lock); \ - spin_unlock(&op->lock); \ - wake_up_interruptible(&orangefs_request_list_waitq); \ -} while (0) - -#define remove_op_from_request_list(op) \ - do { \ - struct list_head *tmp = NULL; \ - struct list_head *tmp_safe = NULL; \ - struct orangefs_kernel_op_s *tmp_op = NULL; \ - \ - spin_lock(&orangefs_request_list_lock); \ - list_for_each_safe(tmp, tmp_safe, &orangefs_request_list) { \ - tmp_op = list_entry(tmp, \ - struct orangefs_kernel_op_s, \ - list); \ - if (tmp_op && (tmp_op == op)) { \ - list_del(&tmp_op->list); \ - break; \ - } \ - } \ - spin_unlock(&orangefs_request_list_lock); \ - } while (0) - -#define ORANGEFS_OP_INTERRUPTIBLE 1 /* service_operation() is interruptible */ -#define ORANGEFS_OP_PRIORITY 2 /* service_operation() is high priority */ -#define ORANGEFS_OP_CANCELLATION 4 /* this is a cancellation */ -#define ORANGEFS_OP_NO_SEMAPHORE 8 /* don't acquire semaphore */ -#define ORANGEFS_OP_ASYNC 16 /* Queue it, but don't wait */ - -int service_operation(struct orangefs_kernel_op_s *op, - const char *op_name, - int flags); - -/* - * handles two possible error cases, depending on context. - * - * by design, our vfs i/o errors need to be handled in one of two ways, - * depending on where the error occured. - * - * if the error happens in the waitqueue code because we either timed - * out or a signal was raised while waiting, we need to cancel the - * userspace i/o operation and free the op manually. this is done to - * avoid having the device start writing application data to our shared - * bufmap pages without us expecting it. - * - * FIXME: POSSIBLE OPTIMIZATION: - * However, if we timed out or if we got a signal AND our upcall was never - * picked off the queue (i.e. we were in OP_VFS_STATE_WAITING), then we don't - * need to send a cancellation upcall. The way we can handle this is - * set error_exit to 2 in such cases and 1 whenever cancellation has to be - * sent and have handle_error - * take care of this situation as well.. - * - * if a orangefs sysint level error occured and i/o has been completed, - * there is no need to cancel the operation, as the user has finished - * using the bufmap page and so there is no danger in this case. in - * this case, we wake up the device normally so that it may free the - * op, as normal. - * - * note the only reason this is a macro is because both read and write - * cases need the exact same handling code. - */ -#define handle_io_error() \ -do { \ - if (!op_state_serviced(new_op)) { \ - orangefs_cancel_op_in_progress(new_op->tag); \ - op_release(new_op); \ - } else { \ - wake_up_daemon_for_return(new_op); \ - } \ - new_op = NULL; \ - orangefs_bufmap_put(bufmap, buffer_index); \ - buffer_index = -1; \ -} while (0) - -#define get_interruptible_flag(inode) \ - ((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \ - ORANGEFS_OP_INTERRUPTIBLE : 0) - -#define add_orangefs_sb(sb) \ -do { \ - gossip_debug(GOSSIP_SUPER_DEBUG, \ - "Adding SB %p to orangefs superblocks\n", \ - ORANGEFS_SB(sb)); \ - spin_lock(&orangefs_superblocks_lock); \ - list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); \ - spin_unlock(&orangefs_superblocks_lock); \ -} while (0) - -#define remove_orangefs_sb(sb) \ -do { \ - struct list_head *tmp = NULL; \ - struct list_head *tmp_safe = NULL; \ - struct orangefs_sb_info_s *orangefs_sb = NULL; \ - \ - spin_lock(&orangefs_superblocks_lock); \ - list_for_each_safe(tmp, tmp_safe, &orangefs_superblocks) { \ - orangefs_sb = list_entry(tmp, \ - struct orangefs_sb_info_s, \ - list); \ - if (orangefs_sb && (orangefs_sb->sb == sb)) { \ - gossip_debug(GOSSIP_SUPER_DEBUG, \ - "Removing SB %p from orangefs superblocks\n", \ - orangefs_sb); \ - list_del(&orangefs_sb->list); \ - break; \ - } \ - } \ - spin_unlock(&orangefs_superblocks_lock); \ -} while (0) - -#define orangefs_lock_inode(inode) spin_lock(&inode->i_lock) -#define orangefs_unlock_inode(inode) spin_unlock(&inode->i_lock) - -#define fill_default_sys_attrs(sys_attr, type, mode) \ -do { \ - sys_attr.owner = from_kuid(current_user_ns(), current_fsuid()); \ - sys_attr.group = from_kgid(current_user_ns(), current_fsgid()); \ - sys_attr.size = 0; \ - sys_attr.perms = ORANGEFS_util_translate_mode(mode); \ - sys_attr.objtype = type; \ - sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE; \ -} while (0) - -#define orangefs_inode_lock(__i) mutex_lock(&(__i)->i_mutex) - -#define orangefs_inode_unlock(__i) mutex_unlock(&(__i)->i_mutex) - -static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size) -{ -#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) - ornagefs_inode_lock(inode); -#endif - i_size_write(inode, i_size); -#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) - orangefs_inode_unlock(inode); -#endif -} - -static inline unsigned int diff(struct timeval *end, struct timeval *begin) -{ - if (end->tv_usec < begin->tv_usec) { - end->tv_usec += 1000000; - end->tv_sec--; - } - end->tv_sec -= begin->tv_sec; - end->tv_usec -= begin->tv_usec; - return (end->tv_sec * 1000000) + end->tv_usec; -} - -#endif /* __ORANGEFSKERNEL_H */ diff --git a/fs/orangefs/pvfs2-mod.c b/fs/orangefs/pvfs2-mod.c deleted file mode 100644 index d8642908a917..000000000000 --- a/fs/orangefs/pvfs2-mod.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * Changes by Acxiom Corporation to add proc file handler for pvfs2 client - * parameters, Copyright Acxiom Corporation, 2005. - * - * See COPYING in top-level directory. - */ - -#include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-debugfs.h" -#include "pvfs2-sysfs.h" - -/* ORANGEFS_VERSION is a ./configure define */ -#ifndef ORANGEFS_VERSION -#define ORANGEFS_VERSION "Unknown" -#endif - -/* - * global variables declared here - */ - -/* array of client debug keyword/mask values */ -struct client_debug_mask *cdm_array; -int cdm_element_count; - -char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN] = "none"; -char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; -char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; - -char *debug_help_string; -int help_string_initialized; -struct dentry *help_file_dentry; -struct dentry *client_debug_dentry; -struct dentry *debug_dir; -int client_verbose_index; -int client_all_index; -struct orangefs_stats g_orangefs_stats; - -/* the size of the hash tables for ops in progress */ -int hash_table_size = 509; - -static ulong module_parm_debug_mask; -__u64 gossip_debug_mask; -struct client_debug_mask client_debug_mask = { NULL, 0, 0 }; -unsigned int kernel_mask_set_mod_init; /* implicitly false */ -int op_timeout_secs = ORANGEFS_DEFAULT_OP_TIMEOUT_SECS; -int slot_timeout_secs = ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS; - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("ORANGEFS Development Team"); -MODULE_DESCRIPTION("The Linux Kernel VFS interface to ORANGEFS"); -MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see orangefs-debug.h for values)"); -MODULE_PARM_DESC(op_timeout_secs, "Operation timeout in seconds"); -MODULE_PARM_DESC(slot_timeout_secs, "Slot timeout in seconds"); -MODULE_PARM_DESC(hash_table_size, - "size of hash table for operations in progress"); - -static struct file_system_type orangefs_fs_type = { - .name = "pvfs2", - .mount = orangefs_mount, - .kill_sb = orangefs_kill_sb, - .owner = THIS_MODULE, -}; - -module_param(hash_table_size, int, 0); -module_param(module_parm_debug_mask, ulong, 0644); -module_param(op_timeout_secs, int, 0); -module_param(slot_timeout_secs, int, 0); - -/* synchronizes the request device file */ -struct mutex devreq_mutex; - -/* - * Blocks non-priority requests from being queued for servicing. This - * could be used for protecting the request list data structure, but - * for now it's only being used to stall the op addition to the request - * list - */ -struct mutex request_mutex; - -/* hash table for storing operations waiting for matching downcall */ -struct list_head *htable_ops_in_progress; -DEFINE_SPINLOCK(htable_ops_in_progress_lock); - -/* list for queueing upcall operations */ -LIST_HEAD(orangefs_request_list); - -/* used to protect the above orangefs_request_list */ -DEFINE_SPINLOCK(orangefs_request_list_lock); - -/* used for incoming request notification */ -DECLARE_WAIT_QUEUE_HEAD(orangefs_request_list_waitq); - -static int __init orangefs_init(void) -{ - int ret = -1; - __u32 i = 0; - - /* convert input debug mask to a 64-bit unsigned integer */ - gossip_debug_mask = (unsigned long long) module_parm_debug_mask; - - /* - * set the kernel's gossip debug string; invalid mask values will - * be ignored. - */ - debug_mask_to_string(&gossip_debug_mask, 0); - - /* remove any invalid values from the mask */ - debug_string_to_mask(kernel_debug_string, &gossip_debug_mask, 0); - - /* - * if the mask has a non-zero value, then indicate that the mask - * was set when the kernel module was loaded. The orangefs dev ioctl - * command will look at this boolean to determine if the kernel's - * debug mask should be overwritten when the client-core is started. - */ - if (gossip_debug_mask != 0) - kernel_mask_set_mod_init = true; - - /* print information message to the system log */ - pr_info("orangefs: orangefs_init called with debug mask: :%s: :%llx:\n", - kernel_debug_string, - (unsigned long long)gossip_debug_mask); - - ret = bdi_init(&orangefs_backing_dev_info); - - if (ret) - return ret; - - if (op_timeout_secs < 0) - op_timeout_secs = 0; - - if (slot_timeout_secs < 0) - slot_timeout_secs = 0; - - /* initialize global book keeping data structures */ - ret = op_cache_initialize(); - if (ret < 0) - goto err; - - ret = dev_req_cache_initialize(); - if (ret < 0) - goto cleanup_op; - - ret = orangefs_inode_cache_initialize(); - if (ret < 0) - goto cleanup_req; - - ret = kiocb_cache_initialize(); - if (ret < 0) - goto cleanup_inode; - - /* Initialize the pvfsdev subsystem. */ - ret = orangefs_dev_init(); - if (ret < 0) { - gossip_err("orangefs: could not initialize device subsystem %d!\n", - ret); - goto cleanup_kiocb; - } - - mutex_init(&devreq_mutex); - mutex_init(&request_mutex); - - htable_ops_in_progress = - kcalloc(hash_table_size, sizeof(struct list_head), GFP_KERNEL); - if (!htable_ops_in_progress) { - gossip_err("Failed to initialize op hashtable"); - ret = -ENOMEM; - goto cleanup_device; - } - - /* initialize a doubly linked at each hash table index */ - for (i = 0; i < hash_table_size; i++) - INIT_LIST_HEAD(&htable_ops_in_progress[i]); - - ret = fsid_key_table_initialize(); - if (ret < 0) - goto cleanup_progress_table; - - /* - * Build the contents of /sys/kernel/debug/orangefs/debug-help - * from the keywords in the kernel keyword/mask array. - * - * The keywords in the client keyword/mask array are - * unknown at boot time. - * - * orangefs_prepare_debugfs_help_string will be used again - * later to rebuild the debug-help file after the client starts - * and passes along the needed info. The argument signifies - * which time orangefs_prepare_debugfs_help_string is being - * called. - * - */ - ret = orangefs_prepare_debugfs_help_string(1); - if (ret) - goto out; - - orangefs_debugfs_init(); - orangefs_kernel_debug_init(); - orangefs_sysfs_init(); - - ret = register_filesystem(&orangefs_fs_type); - if (ret == 0) { - pr_info("orangefs: module version %s loaded\n", ORANGEFS_VERSION); - return 0; - } - - orangefs_debugfs_cleanup(); - orangefs_sysfs_exit(); - fsid_key_table_finalize(); - -cleanup_progress_table: - kfree(htable_ops_in_progress); - -cleanup_device: - orangefs_dev_cleanup(); - -cleanup_kiocb: - kiocb_cache_finalize(); - -cleanup_inode: - orangefs_inode_cache_finalize(); - -cleanup_req: - dev_req_cache_finalize(); - -cleanup_op: - op_cache_finalize(); - -err: - bdi_destroy(&orangefs_backing_dev_info); - -out: - return ret; -} - -static void __exit orangefs_exit(void) -{ - int i = 0; - struct orangefs_kernel_op_s *cur_op = NULL; - - gossip_debug(GOSSIP_INIT_DEBUG, "orangefs: orangefs_exit called\n"); - - unregister_filesystem(&orangefs_fs_type); - orangefs_debugfs_cleanup(); - orangefs_sysfs_exit(); - fsid_key_table_finalize(); - orangefs_dev_cleanup(); - /* clear out all pending upcall op requests */ - spin_lock(&orangefs_request_list_lock); - while (!list_empty(&orangefs_request_list)) { - cur_op = list_entry(orangefs_request_list.next, - struct orangefs_kernel_op_s, - list); - list_del(&cur_op->list); - gossip_debug(GOSSIP_INIT_DEBUG, - "Freeing unhandled upcall request type %d\n", - cur_op->upcall.type); - op_release(cur_op); - } - spin_unlock(&orangefs_request_list_lock); - - for (i = 0; i < hash_table_size; i++) - while (!list_empty(&htable_ops_in_progress[i])) { - cur_op = list_entry(htable_ops_in_progress[i].next, - struct orangefs_kernel_op_s, - list); - op_release(cur_op); - } - - kiocb_cache_finalize(); - orangefs_inode_cache_finalize(); - dev_req_cache_finalize(); - op_cache_finalize(); - - kfree(htable_ops_in_progress); - - bdi_destroy(&orangefs_backing_dev_info); - - pr_info("orangefs: module version %s unloaded\n", ORANGEFS_VERSION); -} - -/* - * What we do in this function is to walk the list of operations - * that are in progress in the hash table and mark them as purged as well. - */ -void purge_inprogress_ops(void) -{ - int i; - - for (i = 0; i < hash_table_size; i++) { - struct orangefs_kernel_op_s *op; - struct orangefs_kernel_op_s *next; - - list_for_each_entry_safe(op, - next, - &htable_ops_in_progress[i], - list) { - spin_lock(&op->lock); - gossip_debug(GOSSIP_INIT_DEBUG, - "pvfs2-client-core: purging in-progress op tag " - "%llu %s\n", - llu(op->tag), - get_opname_string(op)); - set_op_state_purged(op); - spin_unlock(&op->lock); - wake_up_interruptible(&op->waitq); - } - } -} - -module_init(orangefs_init); -module_exit(orangefs_exit); diff --git a/fs/orangefs/pvfs2-sysfs.c b/fs/orangefs/pvfs2-sysfs.c deleted file mode 100644 index f04de2593c79..000000000000 --- a/fs/orangefs/pvfs2-sysfs.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * Documentation/ABI/stable/orangefs-sysfs: - * - * What: /sys/fs/orangefs/perf_counter_reset - * Date: June 2015 - * Contact: Mike Marshall - * Description: - * echo a 0 or a 1 into perf_counter_reset to - * reset all the counters in - * /sys/fs/orangefs/perf_counters - * except ones with PINT_PERF_PRESERVE set. - * - * - * What: /sys/fs/orangefs/perf_counters/... - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Counters and settings for various caches. - * Read only. - * - * - * What: /sys/fs/orangefs/perf_time_interval_secs - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Length of perf counter intervals in - * seconds. - * - * - * What: /sys/fs/orangefs/perf_history_size - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * The perf_counters cache statistics have N, or - * perf_history_size, samples. The default is - * one. - * - * Every perf_time_interval_secs the (first) - * samples are reset. - * - * If N is greater than one, the "current" set - * of samples is reset, and the samples from the - * other N-1 intervals remain available. - * - * - * What: /sys/fs/orangefs/op_timeout_secs - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Service operation timeout in seconds. - * - * - * What: /sys/fs/orangefs/slot_timeout_secs - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * "Slot" timeout in seconds. A "slot" - * is an indexed buffer in the shared - * memory segment used for communication - * between the kernel module and userspace. - * Slots are requested and waited for, - * the wait times out after slot_timeout_secs. - * - * - * What: /sys/fs/orangefs/acache/... - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Attribute cache configurable settings. - * - * - * What: /sys/fs/orangefs/ncache/... - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Name cache configurable settings. - * - * - * What: /sys/fs/orangefs/capcache/... - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Capability cache configurable settings. - * - * - * What: /sys/fs/orangefs/ccache/... - * Date: Jun 2015 - * Contact: Mike Marshall - * Description: - * Credential cache configurable settings. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-sysfs.h" - -#define ORANGEFS_KOBJ_ID "orangefs" -#define ACACHE_KOBJ_ID "acache" -#define CAPCACHE_KOBJ_ID "capcache" -#define CCACHE_KOBJ_ID "ccache" -#define NCACHE_KOBJ_ID "ncache" -#define PC_KOBJ_ID "pc" -#define STATS_KOBJ_ID "stats" - -struct orangefs_obj { - struct kobject kobj; - int op_timeout_secs; - int perf_counter_reset; - int perf_history_size; - int perf_time_interval_secs; - int slot_timeout_secs; -}; - -struct acache_orangefs_obj { - struct kobject kobj; - int hard_limit; - int reclaim_percentage; - int soft_limit; - int timeout_msecs; -}; - -struct capcache_orangefs_obj { - struct kobject kobj; - int hard_limit; - int reclaim_percentage; - int soft_limit; - int timeout_secs; -}; - -struct ccache_orangefs_obj { - struct kobject kobj; - int hard_limit; - int reclaim_percentage; - int soft_limit; - int timeout_secs; -}; - -struct ncache_orangefs_obj { - struct kobject kobj; - int hard_limit; - int reclaim_percentage; - int soft_limit; - int timeout_msecs; -}; - -struct pc_orangefs_obj { - struct kobject kobj; - char *acache; - char *capcache; - char *ncache; -}; - -struct stats_orangefs_obj { - struct kobject kobj; - int reads; - int writes; -}; - -struct orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct orangefs_obj *orangefs_obj, - struct orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct orangefs_obj *orangefs_obj, - struct orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -struct acache_orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct acache_orangefs_obj *acache_orangefs_obj, - struct acache_orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct acache_orangefs_obj *acache_orangefs_obj, - struct acache_orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -struct capcache_orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct capcache_orangefs_obj *capcache_orangefs_obj, - struct capcache_orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct capcache_orangefs_obj *capcache_orangefs_obj, - struct capcache_orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -struct ccache_orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct ccache_orangefs_obj *ccache_orangefs_obj, - struct ccache_orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct ccache_orangefs_obj *ccache_orangefs_obj, - struct ccache_orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -struct ncache_orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct ncache_orangefs_obj *ncache_orangefs_obj, - struct ncache_orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct ncache_orangefs_obj *ncache_orangefs_obj, - struct ncache_orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -struct pc_orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct pc_orangefs_obj *pc_orangefs_obj, - struct pc_orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct pc_orangefs_obj *pc_orangefs_obj, - struct pc_orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -struct stats_orangefs_attribute { - struct attribute attr; - ssize_t (*show)(struct stats_orangefs_obj *stats_orangefs_obj, - struct stats_orangefs_attribute *attr, - char *buf); - ssize_t (*store)(struct stats_orangefs_obj *stats_orangefs_obj, - struct stats_orangefs_attribute *attr, - const char *buf, - size_t count); -}; - -static ssize_t orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct orangefs_attribute *attribute; - struct orangefs_obj *orangefs_obj; - int rc; - - attribute = container_of(attr, struct orangefs_attribute, attr); - orangefs_obj = container_of(kobj, struct orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(orangefs_obj, attribute, buf); - -out: - return rc; -} - -static ssize_t orangefs_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t len) -{ - struct orangefs_attribute *attribute; - struct orangefs_obj *orangefs_obj; - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "orangefs_attr_store: start\n"); - - attribute = container_of(attr, struct orangefs_attribute, attr); - orangefs_obj = container_of(kobj, struct orangefs_obj, kobj); - - if (!attribute->store) { - rc = -EIO; - goto out; - } - - rc = attribute->store(orangefs_obj, attribute, buf, len); - -out: - return rc; -} - -static const struct sysfs_ops orangefs_sysfs_ops = { - .show = orangefs_attr_show, - .store = orangefs_attr_store, -}; - -static ssize_t acache_orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct acache_orangefs_attribute *attribute; - struct acache_orangefs_obj *acache_orangefs_obj; - int rc; - - attribute = container_of(attr, struct acache_orangefs_attribute, attr); - acache_orangefs_obj = - container_of(kobj, struct acache_orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(acache_orangefs_obj, attribute, buf); - -out: - return rc; -} - -static ssize_t acache_orangefs_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t len) -{ - struct acache_orangefs_attribute *attribute; - struct acache_orangefs_obj *acache_orangefs_obj; - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "acache_orangefs_attr_store: start\n"); - - attribute = container_of(attr, struct acache_orangefs_attribute, attr); - acache_orangefs_obj = - container_of(kobj, struct acache_orangefs_obj, kobj); - - if (!attribute->store) { - rc = -EIO; - goto out; - } - - rc = attribute->store(acache_orangefs_obj, attribute, buf, len); - -out: - return rc; -} - -static const struct sysfs_ops acache_orangefs_sysfs_ops = { - .show = acache_orangefs_attr_show, - .store = acache_orangefs_attr_store, -}; - -static ssize_t capcache_orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct capcache_orangefs_attribute *attribute; - struct capcache_orangefs_obj *capcache_orangefs_obj; - int rc; - - attribute = - container_of(attr, struct capcache_orangefs_attribute, attr); - capcache_orangefs_obj = - container_of(kobj, struct capcache_orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(capcache_orangefs_obj, attribute, buf); - -out: - return rc; -} - -static ssize_t capcache_orangefs_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t len) -{ - struct capcache_orangefs_attribute *attribute; - struct capcache_orangefs_obj *capcache_orangefs_obj; - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "capcache_orangefs_attr_store: start\n"); - - attribute = - container_of(attr, struct capcache_orangefs_attribute, attr); - capcache_orangefs_obj = - container_of(kobj, struct capcache_orangefs_obj, kobj); - - if (!attribute->store) { - rc = -EIO; - goto out; - } - - rc = attribute->store(capcache_orangefs_obj, attribute, buf, len); - -out: - return rc; -} - -static const struct sysfs_ops capcache_orangefs_sysfs_ops = { - .show = capcache_orangefs_attr_show, - .store = capcache_orangefs_attr_store, -}; - -static ssize_t ccache_orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct ccache_orangefs_attribute *attribute; - struct ccache_orangefs_obj *ccache_orangefs_obj; - int rc; - - attribute = - container_of(attr, struct ccache_orangefs_attribute, attr); - ccache_orangefs_obj = - container_of(kobj, struct ccache_orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(ccache_orangefs_obj, attribute, buf); - -out: - return rc; -} - -static ssize_t ccache_orangefs_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t len) -{ - struct ccache_orangefs_attribute *attribute; - struct ccache_orangefs_obj *ccache_orangefs_obj; - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "ccache_orangefs_attr_store: start\n"); - - attribute = - container_of(attr, struct ccache_orangefs_attribute, attr); - ccache_orangefs_obj = - container_of(kobj, struct ccache_orangefs_obj, kobj); - - if (!attribute->store) { - rc = -EIO; - goto out; - } - - rc = attribute->store(ccache_orangefs_obj, attribute, buf, len); - -out: - return rc; -} - -static const struct sysfs_ops ccache_orangefs_sysfs_ops = { - .show = ccache_orangefs_attr_show, - .store = ccache_orangefs_attr_store, -}; - -static ssize_t ncache_orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct ncache_orangefs_attribute *attribute; - struct ncache_orangefs_obj *ncache_orangefs_obj; - int rc; - - attribute = container_of(attr, struct ncache_orangefs_attribute, attr); - ncache_orangefs_obj = - container_of(kobj, struct ncache_orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(ncache_orangefs_obj, attribute, buf); - -out: - return rc; -} - -static ssize_t ncache_orangefs_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t len) -{ - struct ncache_orangefs_attribute *attribute; - struct ncache_orangefs_obj *ncache_orangefs_obj; - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "ncache_orangefs_attr_store: start\n"); - - attribute = container_of(attr, struct ncache_orangefs_attribute, attr); - ncache_orangefs_obj = - container_of(kobj, struct ncache_orangefs_obj, kobj); - - if (!attribute->store) { - rc = -EIO; - goto out; - } - - rc = attribute->store(ncache_orangefs_obj, attribute, buf, len); - -out: - return rc; -} - -static const struct sysfs_ops ncache_orangefs_sysfs_ops = { - .show = ncache_orangefs_attr_show, - .store = ncache_orangefs_attr_store, -}; - -static ssize_t pc_orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct pc_orangefs_attribute *attribute; - struct pc_orangefs_obj *pc_orangefs_obj; - int rc; - - attribute = container_of(attr, struct pc_orangefs_attribute, attr); - pc_orangefs_obj = - container_of(kobj, struct pc_orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(pc_orangefs_obj, attribute, buf); - -out: - return rc; -} - -static const struct sysfs_ops pc_orangefs_sysfs_ops = { - .show = pc_orangefs_attr_show, -}; - -static ssize_t stats_orangefs_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct stats_orangefs_attribute *attribute; - struct stats_orangefs_obj *stats_orangefs_obj; - int rc; - - attribute = container_of(attr, struct stats_orangefs_attribute, attr); - stats_orangefs_obj = - container_of(kobj, struct stats_orangefs_obj, kobj); - - if (!attribute->show) { - rc = -EIO; - goto out; - } - - rc = attribute->show(stats_orangefs_obj, attribute, buf); - -out: - return rc; -} - -static const struct sysfs_ops stats_orangefs_sysfs_ops = { - .show = stats_orangefs_attr_show, -}; - -static void orangefs_release(struct kobject *kobj) -{ - struct orangefs_obj *orangefs_obj; - - orangefs_obj = container_of(kobj, struct orangefs_obj, kobj); - kfree(orangefs_obj); -} - -static void acache_orangefs_release(struct kobject *kobj) -{ - struct acache_orangefs_obj *acache_orangefs_obj; - - acache_orangefs_obj = - container_of(kobj, struct acache_orangefs_obj, kobj); - kfree(acache_orangefs_obj); -} - -static void capcache_orangefs_release(struct kobject *kobj) -{ - struct capcache_orangefs_obj *capcache_orangefs_obj; - - capcache_orangefs_obj = - container_of(kobj, struct capcache_orangefs_obj, kobj); - kfree(capcache_orangefs_obj); -} - -static void ccache_orangefs_release(struct kobject *kobj) -{ - struct ccache_orangefs_obj *ccache_orangefs_obj; - - ccache_orangefs_obj = - container_of(kobj, struct ccache_orangefs_obj, kobj); - kfree(ccache_orangefs_obj); -} - -static void ncache_orangefs_release(struct kobject *kobj) -{ - struct ncache_orangefs_obj *ncache_orangefs_obj; - - ncache_orangefs_obj = - container_of(kobj, struct ncache_orangefs_obj, kobj); - kfree(ncache_orangefs_obj); -} - -static void pc_orangefs_release(struct kobject *kobj) -{ - struct pc_orangefs_obj *pc_orangefs_obj; - - pc_orangefs_obj = - container_of(kobj, struct pc_orangefs_obj, kobj); - kfree(pc_orangefs_obj); -} - -static void stats_orangefs_release(struct kobject *kobj) -{ - struct stats_orangefs_obj *stats_orangefs_obj; - - stats_orangefs_obj = - container_of(kobj, struct stats_orangefs_obj, kobj); - kfree(stats_orangefs_obj); -} - -static ssize_t sysfs_int_show(char *kobj_id, char *buf, void *attr) -{ - int rc = -EIO; - struct orangefs_attribute *orangefs_attr; - struct stats_orangefs_attribute *stats_orangefs_attr; - - gossip_debug(GOSSIP_SYSFS_DEBUG, "sysfs_int_show: id:%s:\n", kobj_id); - - if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { - orangefs_attr = (struct orangefs_attribute *)attr; - - if (!strcmp(orangefs_attr->attr.name, "op_timeout_secs")) { - rc = scnprintf(buf, - PAGE_SIZE, - "%d\n", - op_timeout_secs); - goto out; - } else if (!strcmp(orangefs_attr->attr.name, - "slot_timeout_secs")) { - rc = scnprintf(buf, - PAGE_SIZE, - "%d\n", - slot_timeout_secs); - goto out; - } else { - goto out; - } - - } else if (!strcmp(kobj_id, STATS_KOBJ_ID)) { - stats_orangefs_attr = (struct stats_orangefs_attribute *)attr; - - if (!strcmp(stats_orangefs_attr->attr.name, "reads")) { - rc = scnprintf(buf, - PAGE_SIZE, - "%lu\n", - g_orangefs_stats.reads); - goto out; - } else if (!strcmp(stats_orangefs_attr->attr.name, "writes")) { - rc = scnprintf(buf, - PAGE_SIZE, - "%lu\n", - g_orangefs_stats.writes); - goto out; - } else { - goto out; - } - } - -out: - - return rc; -} - -static ssize_t int_orangefs_show(struct orangefs_obj *orangefs_obj, - struct orangefs_attribute *attr, - char *buf) -{ - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "int_orangefs_show:start attr->attr.name:%s:\n", - attr->attr.name); - - rc = sysfs_int_show(ORANGEFS_KOBJ_ID, buf, (void *) attr); - - return rc; -} - -static ssize_t int_stats_show(struct stats_orangefs_obj *stats_orangefs_obj, - struct stats_orangefs_attribute *attr, - char *buf) -{ - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "int_stats_show:start attr->attr.name:%s:\n", - attr->attr.name); - - rc = sysfs_int_show(STATS_KOBJ_ID, buf, (void *) attr); - - return rc; -} - -static ssize_t int_store(struct orangefs_obj *orangefs_obj, - struct orangefs_attribute *attr, - const char *buf, - size_t count) -{ - int rc = 0; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "int_store: start attr->attr.name:%s: buf:%s:\n", - attr->attr.name, buf); - - if (!strcmp(attr->attr.name, "op_timeout_secs")) { - rc = kstrtoint(buf, 0, &op_timeout_secs); - goto out; - } else if (!strcmp(attr->attr.name, "slot_timeout_secs")) { - rc = kstrtoint(buf, 0, &slot_timeout_secs); - goto out; - } else { - goto out; - } - -out: - if (rc) - rc = -EINVAL; - else - rc = count; - - return rc; -} - -/* - * obtain attribute values from userspace with a service operation. - */ -static int sysfs_service_op_show(char *kobj_id, char *buf, void *attr) -{ - struct orangefs_kernel_op_s *new_op = NULL; - int rc = 0; - char *ser_op_type = NULL; - struct orangefs_attribute *orangefs_attr; - struct acache_orangefs_attribute *acache_attr; - struct capcache_orangefs_attribute *capcache_attr; - struct ccache_orangefs_attribute *ccache_attr; - struct ncache_orangefs_attribute *ncache_attr; - struct pc_orangefs_attribute *pc_attr; - __u32 op_alloc_type; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "sysfs_service_op_show: id:%s:\n", - kobj_id); - - if (strcmp(kobj_id, PC_KOBJ_ID)) - op_alloc_type = ORANGEFS_VFS_OP_PARAM; - else - op_alloc_type = ORANGEFS_VFS_OP_PERF_COUNT; - - new_op = op_alloc(op_alloc_type); - if (!new_op) { - rc = -ENOMEM; - goto out; - } - - /* Can't do a service_operation if the client is not running... */ - rc = is_daemon_in_service(); - if (rc) { - pr_info("%s: Client not running :%d:\n", - __func__, - is_daemon_in_service()); - goto out; - } - - if (strcmp(kobj_id, PC_KOBJ_ID)) - new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_GET; - - if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { - orangefs_attr = (struct orangefs_attribute *)attr; - - if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE; - else if (!strcmp(orangefs_attr->attr.name, - "perf_time_interval_secs")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS; - else if (!strcmp(orangefs_attr->attr.name, - "perf_counter_reset")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_PERF_RESET; - - } else if (!strcmp(kobj_id, ACACHE_KOBJ_ID)) { - acache_attr = (struct acache_orangefs_attribute *)attr; - - if (!strcmp(acache_attr->attr.name, "timeout_msecs")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS; - - if (!strcmp(acache_attr->attr.name, "hard_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT; - - if (!strcmp(acache_attr->attr.name, "soft_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT; - - if (!strcmp(acache_attr->attr.name, "reclaim_percentage")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE; - - } else if (!strcmp(kobj_id, CAPCACHE_KOBJ_ID)) { - capcache_attr = (struct capcache_orangefs_attribute *)attr; - - if (!strcmp(capcache_attr->attr.name, "timeout_secs")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS; - - if (!strcmp(capcache_attr->attr.name, "hard_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT; - - if (!strcmp(capcache_attr->attr.name, "soft_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT; - - if (!strcmp(capcache_attr->attr.name, "reclaim_percentage")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE; - - } else if (!strcmp(kobj_id, CCACHE_KOBJ_ID)) { - ccache_attr = (struct ccache_orangefs_attribute *)attr; - - if (!strcmp(ccache_attr->attr.name, "timeout_secs")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS; - - if (!strcmp(ccache_attr->attr.name, "hard_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT; - - if (!strcmp(ccache_attr->attr.name, "soft_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT; - - if (!strcmp(ccache_attr->attr.name, "reclaim_percentage")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE; - - } else if (!strcmp(kobj_id, NCACHE_KOBJ_ID)) { - ncache_attr = (struct ncache_orangefs_attribute *)attr; - - if (!strcmp(ncache_attr->attr.name, "timeout_msecs")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS; - - if (!strcmp(ncache_attr->attr.name, "hard_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT; - - if (!strcmp(ncache_attr->attr.name, "soft_limit")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT; - - if (!strcmp(ncache_attr->attr.name, "reclaim_percentage")) - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE; - - } else if (!strcmp(kobj_id, PC_KOBJ_ID)) { - pc_attr = (struct pc_orangefs_attribute *)attr; - - if (!strcmp(pc_attr->attr.name, ACACHE_KOBJ_ID)) - new_op->upcall.req.perf_count.type = - ORANGEFS_PERF_COUNT_REQUEST_ACACHE; - - if (!strcmp(pc_attr->attr.name, CAPCACHE_KOBJ_ID)) - new_op->upcall.req.perf_count.type = - ORANGEFS_PERF_COUNT_REQUEST_CAPCACHE; - - if (!strcmp(pc_attr->attr.name, NCACHE_KOBJ_ID)) - new_op->upcall.req.perf_count.type = - ORANGEFS_PERF_COUNT_REQUEST_NCACHE; - - } else { - gossip_err("sysfs_service_op_show: unknown kobj_id:%s:\n", - kobj_id); - rc = -EINVAL; - goto out; - } - - - if (strcmp(kobj_id, PC_KOBJ_ID)) - ser_op_type = "orangefs_param"; - else - ser_op_type = "orangefs_perf_count"; - - /* - * The service_operation will return an errno return code on - * error, and zero on success. - */ - rc = service_operation(new_op, ser_op_type, ORANGEFS_OP_INTERRUPTIBLE); - -out: - if (!rc) { - if (strcmp(kobj_id, PC_KOBJ_ID)) { - rc = scnprintf(buf, - PAGE_SIZE, - "%d\n", - (int)new_op->downcall.resp.param.value); - } else { - rc = scnprintf( - buf, - PAGE_SIZE, - "%s", - new_op->downcall.resp.perf_count.buffer); - } - } - - /* - * if we got ENOMEM, then op_alloc probably failed... - */ - if (rc != -ENOMEM) - op_release(new_op); - - return rc; - -} - -static ssize_t service_orangefs_show(struct orangefs_obj *orangefs_obj, - struct orangefs_attribute *attr, - char *buf) -{ - int rc = 0; - - rc = sysfs_service_op_show(ORANGEFS_KOBJ_ID, buf, (void *)attr); - - return rc; -} - -static ssize_t - service_acache_show(struct acache_orangefs_obj *acache_orangefs_obj, - struct acache_orangefs_attribute *attr, - char *buf) -{ - int rc = 0; - - rc = sysfs_service_op_show(ACACHE_KOBJ_ID, buf, (void *)attr); - - return rc; -} - -static ssize_t service_capcache_show(struct capcache_orangefs_obj - *capcache_orangefs_obj, - struct capcache_orangefs_attribute *attr, - char *buf) -{ - int rc = 0; - - rc = sysfs_service_op_show(CAPCACHE_KOBJ_ID, buf, (void *)attr); - - return rc; -} - -static ssize_t service_ccache_show(struct ccache_orangefs_obj - *ccache_orangefs_obj, - struct ccache_orangefs_attribute *attr, - char *buf) -{ - int rc = 0; - - rc = sysfs_service_op_show(CCACHE_KOBJ_ID, buf, (void *)attr); - - return rc; -} - -static ssize_t - service_ncache_show(struct ncache_orangefs_obj *ncache_orangefs_obj, - struct ncache_orangefs_attribute *attr, - char *buf) -{ - int rc = 0; - - rc = sysfs_service_op_show(NCACHE_KOBJ_ID, buf, (void *)attr); - - return rc; -} - -static ssize_t - service_pc_show(struct pc_orangefs_obj *pc_orangefs_obj, - struct pc_orangefs_attribute *attr, - char *buf) -{ - int rc = 0; - - rc = sysfs_service_op_show(PC_KOBJ_ID, buf, (void *)attr); - - return rc; -} - -/* - * pass attribute values back to userspace with a service operation. - * - * We have to do a memory allocation, an sscanf and a service operation. - * And we have to evaluate what the user entered, to make sure the - * value is within the range supported by the attribute. So, there's - * a lot of return code checking and mapping going on here. - * - * We want to return 1 if we think everything went OK, and - * EINVAL if not. - */ -static int sysfs_service_op_store(char *kobj_id, const char *buf, void *attr) -{ - struct orangefs_kernel_op_s *new_op = NULL; - int val = 0; - int rc = 0; - struct orangefs_attribute *orangefs_attr; - struct acache_orangefs_attribute *acache_attr; - struct capcache_orangefs_attribute *capcache_attr; - struct ccache_orangefs_attribute *ccache_attr; - struct ncache_orangefs_attribute *ncache_attr; - - gossip_debug(GOSSIP_SYSFS_DEBUG, - "sysfs_service_op_store: id:%s:\n", - kobj_id); - - new_op = op_alloc(ORANGEFS_VFS_OP_PARAM); - if (!new_op) { - rc = -ENOMEM; - goto out; - } - - /* Can't do a service_operation if the client is not running... */ - rc = is_daemon_in_service(); - if (rc) { - pr_info("%s: Client not running :%d:\n", - __func__, - is_daemon_in_service()); - goto out; - } - - /* - * The value we want to send back to userspace is in buf. - */ - rc = kstrtoint(buf, 0, &val); - if (rc) - goto out; - - if (!strcmp(kobj_id, ORANGEFS_KOBJ_ID)) { - orangefs_attr = (struct orangefs_attribute *)attr; - - if (!strcmp(orangefs_attr->attr.name, "perf_history_size")) { - if (val > 0) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_PERF_HISTORY_SIZE; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(orangefs_attr->attr.name, - "perf_time_interval_secs")) { - if (val > 0) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_PERF_TIME_INTERVAL_SECS; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(orangefs_attr->attr.name, - "perf_counter_reset")) { - if ((val == 0) || (val == 1)) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_PERF_RESET; - } else { - rc = 0; - goto out; - } - } - - } else if (!strcmp(kobj_id, ACACHE_KOBJ_ID)) { - acache_attr = (struct acache_orangefs_attribute *)attr; - - if (!strcmp(acache_attr->attr.name, "hard_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_HARD_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(acache_attr->attr.name, "soft_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_SOFT_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(acache_attr->attr.name, - "reclaim_percentage")) { - if ((val > -1) && (val < 101)) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_RECLAIM_PERCENTAGE; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(acache_attr->attr.name, "timeout_msecs")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_ACACHE_TIMEOUT_MSECS; - } else { - rc = 0; - goto out; - } - } - - } else if (!strcmp(kobj_id, CAPCACHE_KOBJ_ID)) { - capcache_attr = (struct capcache_orangefs_attribute *)attr; - - if (!strcmp(capcache_attr->attr.name, "hard_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_HARD_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(capcache_attr->attr.name, "soft_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_SOFT_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(capcache_attr->attr.name, - "reclaim_percentage")) { - if ((val > -1) && (val < 101)) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_RECLAIM_PERCENTAGE; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(capcache_attr->attr.name, "timeout_secs")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CAPCACHE_TIMEOUT_SECS; - } else { - rc = 0; - goto out; - } - } - - } else if (!strcmp(kobj_id, CCACHE_KOBJ_ID)) { - ccache_attr = (struct ccache_orangefs_attribute *)attr; - - if (!strcmp(ccache_attr->attr.name, "hard_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_HARD_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(ccache_attr->attr.name, "soft_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_SOFT_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(ccache_attr->attr.name, - "reclaim_percentage")) { - if ((val > -1) && (val < 101)) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_RECLAIM_PERCENTAGE; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(ccache_attr->attr.name, "timeout_secs")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_CCACHE_TIMEOUT_SECS; - } else { - rc = 0; - goto out; - } - } - - } else if (!strcmp(kobj_id, NCACHE_KOBJ_ID)) { - ncache_attr = (struct ncache_orangefs_attribute *)attr; - - if (!strcmp(ncache_attr->attr.name, "hard_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_HARD_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(ncache_attr->attr.name, "soft_limit")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_SOFT_LIMIT; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(ncache_attr->attr.name, - "reclaim_percentage")) { - if ((val > -1) && (val < 101)) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_RECLAIM_PERCENTAGE; - } else { - rc = 0; - goto out; - } - } else if (!strcmp(ncache_attr->attr.name, "timeout_msecs")) { - if (val > -1) { - new_op->upcall.req.param.op = - ORANGEFS_PARAM_REQUEST_OP_NCACHE_TIMEOUT_MSECS; - } else { - rc = 0; - goto out; - } - } - - } else { - gossip_err("sysfs_service_op_store: unknown kobj_id:%s:\n", - kobj_id); - rc = -EINVAL; - goto out; - } - - new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET; - - new_op->upcall.req.param.value = val; - - /* - * The service_operation will return a errno return code on - * error, and zero on success. - */ - rc = service_operation(new_op, "orangefs_param", ORANGEFS_OP_INTERRUPTIBLE); - - if (rc < 0) { - gossip_err("sysfs_service_op_store: service op returned:%d:\n", - rc); - rc = 0; - } else { - rc = 1; - } - -out: - /* - * if we got ENOMEM, then op_alloc probably failed... - */ - if (rc == -ENOMEM) - rc = 0; - else - op_release(new_op); - - if (rc == 0) - rc = -EINVAL; - - return rc; -} - -static ssize_t - service_orangefs_store(struct orangefs_obj *orangefs_obj, - struct orangefs_attribute *attr, - const char *buf, - size_t count) -{ - int rc = 0; - - rc = sysfs_service_op_store(ORANGEFS_KOBJ_ID, buf, (void *) attr); - - /* rc should have an errno value if the service_op went bad. */ - if (rc == 1) - rc = count; - - return rc; -} - -static ssize_t - service_acache_store(struct acache_orangefs_obj *acache_orangefs_obj, - struct acache_orangefs_attribute *attr, - const char *buf, - size_t count) -{ - int rc = 0; - - rc = sysfs_service_op_store(ACACHE_KOBJ_ID, buf, (void *) attr); - - /* rc should have an errno value if the service_op went bad. */ - if (rc == 1) - rc = count; - - return rc; -} - -static ssize_t - service_capcache_store(struct capcache_orangefs_obj - *capcache_orangefs_obj, - struct capcache_orangefs_attribute *attr, - const char *buf, - size_t count) -{ - int rc = 0; - - rc = sysfs_service_op_store(CAPCACHE_KOBJ_ID, buf, (void *) attr); - - /* rc should have an errno value if the service_op went bad. */ - if (rc == 1) - rc = count; - - return rc; -} - -static ssize_t service_ccache_store(struct ccache_orangefs_obj - *ccache_orangefs_obj, - struct ccache_orangefs_attribute *attr, - const char *buf, - size_t count) -{ - int rc = 0; - - rc = sysfs_service_op_store(CCACHE_KOBJ_ID, buf, (void *) attr); - - /* rc should have an errno value if the service_op went bad. */ - if (rc == 1) - rc = count; - - return rc; -} - -static ssize_t - service_ncache_store(struct ncache_orangefs_obj *ncache_orangefs_obj, - struct ncache_orangefs_attribute *attr, - const char *buf, - size_t count) -{ - int rc = 0; - - rc = sysfs_service_op_store(NCACHE_KOBJ_ID, buf, (void *) attr); - - /* rc should have an errno value if the service_op went bad. */ - if (rc == 1) - rc = count; - - return rc; -} - -static struct orangefs_attribute op_timeout_secs_attribute = - __ATTR(op_timeout_secs, 0664, int_orangefs_show, int_store); - -static struct orangefs_attribute slot_timeout_secs_attribute = - __ATTR(slot_timeout_secs, 0664, int_orangefs_show, int_store); - -static struct orangefs_attribute perf_counter_reset_attribute = - __ATTR(perf_counter_reset, - 0664, - service_orangefs_show, - service_orangefs_store); - -static struct orangefs_attribute perf_history_size_attribute = - __ATTR(perf_history_size, - 0664, - service_orangefs_show, - service_orangefs_store); - -static struct orangefs_attribute perf_time_interval_secs_attribute = - __ATTR(perf_time_interval_secs, - 0664, - service_orangefs_show, - service_orangefs_store); - -static struct attribute *orangefs_default_attrs[] = { - &op_timeout_secs_attribute.attr, - &slot_timeout_secs_attribute.attr, - &perf_counter_reset_attribute.attr, - &perf_history_size_attribute.attr, - &perf_time_interval_secs_attribute.attr, - NULL, -}; - -static struct kobj_type orangefs_ktype = { - .sysfs_ops = &orangefs_sysfs_ops, - .release = orangefs_release, - .default_attrs = orangefs_default_attrs, -}; - -static struct acache_orangefs_attribute acache_hard_limit_attribute = - __ATTR(hard_limit, - 0664, - service_acache_show, - service_acache_store); - -static struct acache_orangefs_attribute acache_reclaim_percent_attribute = - __ATTR(reclaim_percentage, - 0664, - service_acache_show, - service_acache_store); - -static struct acache_orangefs_attribute acache_soft_limit_attribute = - __ATTR(soft_limit, - 0664, - service_acache_show, - service_acache_store); - -static struct acache_orangefs_attribute acache_timeout_msecs_attribute = - __ATTR(timeout_msecs, - 0664, - service_acache_show, - service_acache_store); - -static struct attribute *acache_orangefs_default_attrs[] = { - &acache_hard_limit_attribute.attr, - &acache_reclaim_percent_attribute.attr, - &acache_soft_limit_attribute.attr, - &acache_timeout_msecs_attribute.attr, - NULL, -}; - -static struct kobj_type acache_orangefs_ktype = { - .sysfs_ops = &acache_orangefs_sysfs_ops, - .release = acache_orangefs_release, - .default_attrs = acache_orangefs_default_attrs, -}; - -static struct capcache_orangefs_attribute capcache_hard_limit_attribute = - __ATTR(hard_limit, - 0664, - service_capcache_show, - service_capcache_store); - -static struct capcache_orangefs_attribute capcache_reclaim_percent_attribute = - __ATTR(reclaim_percentage, - 0664, - service_capcache_show, - service_capcache_store); - -static struct capcache_orangefs_attribute capcache_soft_limit_attribute = - __ATTR(soft_limit, - 0664, - service_capcache_show, - service_capcache_store); - -static struct capcache_orangefs_attribute capcache_timeout_secs_attribute = - __ATTR(timeout_secs, - 0664, - service_capcache_show, - service_capcache_store); - -static struct attribute *capcache_orangefs_default_attrs[] = { - &capcache_hard_limit_attribute.attr, - &capcache_reclaim_percent_attribute.attr, - &capcache_soft_limit_attribute.attr, - &capcache_timeout_secs_attribute.attr, - NULL, -}; - -static struct kobj_type capcache_orangefs_ktype = { - .sysfs_ops = &capcache_orangefs_sysfs_ops, - .release = capcache_orangefs_release, - .default_attrs = capcache_orangefs_default_attrs, -}; - -static struct ccache_orangefs_attribute ccache_hard_limit_attribute = - __ATTR(hard_limit, - 0664, - service_ccache_show, - service_ccache_store); - -static struct ccache_orangefs_attribute ccache_reclaim_percent_attribute = - __ATTR(reclaim_percentage, - 0664, - service_ccache_show, - service_ccache_store); - -static struct ccache_orangefs_attribute ccache_soft_limit_attribute = - __ATTR(soft_limit, - 0664, - service_ccache_show, - service_ccache_store); - -static struct ccache_orangefs_attribute ccache_timeout_secs_attribute = - __ATTR(timeout_secs, - 0664, - service_ccache_show, - service_ccache_store); - -static struct attribute *ccache_orangefs_default_attrs[] = { - &ccache_hard_limit_attribute.attr, - &ccache_reclaim_percent_attribute.attr, - &ccache_soft_limit_attribute.attr, - &ccache_timeout_secs_attribute.attr, - NULL, -}; - -static struct kobj_type ccache_orangefs_ktype = { - .sysfs_ops = &ccache_orangefs_sysfs_ops, - .release = ccache_orangefs_release, - .default_attrs = ccache_orangefs_default_attrs, -}; - -static struct ncache_orangefs_attribute ncache_hard_limit_attribute = - __ATTR(hard_limit, - 0664, - service_ncache_show, - service_ncache_store); - -static struct ncache_orangefs_attribute ncache_reclaim_percent_attribute = - __ATTR(reclaim_percentage, - 0664, - service_ncache_show, - service_ncache_store); - -static struct ncache_orangefs_attribute ncache_soft_limit_attribute = - __ATTR(soft_limit, - 0664, - service_ncache_show, - service_ncache_store); - -static struct ncache_orangefs_attribute ncache_timeout_msecs_attribute = - __ATTR(timeout_msecs, - 0664, - service_ncache_show, - service_ncache_store); - -static struct attribute *ncache_orangefs_default_attrs[] = { - &ncache_hard_limit_attribute.attr, - &ncache_reclaim_percent_attribute.attr, - &ncache_soft_limit_attribute.attr, - &ncache_timeout_msecs_attribute.attr, - NULL, -}; - -static struct kobj_type ncache_orangefs_ktype = { - .sysfs_ops = &ncache_orangefs_sysfs_ops, - .release = ncache_orangefs_release, - .default_attrs = ncache_orangefs_default_attrs, -}; - -static struct pc_orangefs_attribute pc_acache_attribute = - __ATTR(acache, - 0664, - service_pc_show, - NULL); - -static struct pc_orangefs_attribute pc_capcache_attribute = - __ATTR(capcache, - 0664, - service_pc_show, - NULL); - -static struct pc_orangefs_attribute pc_ncache_attribute = - __ATTR(ncache, - 0664, - service_pc_show, - NULL); - -static struct attribute *pc_orangefs_default_attrs[] = { - &pc_acache_attribute.attr, - &pc_capcache_attribute.attr, - &pc_ncache_attribute.attr, - NULL, -}; - -static struct kobj_type pc_orangefs_ktype = { - .sysfs_ops = &pc_orangefs_sysfs_ops, - .release = pc_orangefs_release, - .default_attrs = pc_orangefs_default_attrs, -}; - -static struct stats_orangefs_attribute stats_reads_attribute = - __ATTR(reads, - 0664, - int_stats_show, - NULL); - -static struct stats_orangefs_attribute stats_writes_attribute = - __ATTR(writes, - 0664, - int_stats_show, - NULL); - -static struct attribute *stats_orangefs_default_attrs[] = { - &stats_reads_attribute.attr, - &stats_writes_attribute.attr, - NULL, -}; - -static struct kobj_type stats_orangefs_ktype = { - .sysfs_ops = &stats_orangefs_sysfs_ops, - .release = stats_orangefs_release, - .default_attrs = stats_orangefs_default_attrs, -}; - -static struct orangefs_obj *orangefs_obj; -static struct acache_orangefs_obj *acache_orangefs_obj; -static struct capcache_orangefs_obj *capcache_orangefs_obj; -static struct ccache_orangefs_obj *ccache_orangefs_obj; -static struct ncache_orangefs_obj *ncache_orangefs_obj; -static struct pc_orangefs_obj *pc_orangefs_obj; -static struct stats_orangefs_obj *stats_orangefs_obj; - -int orangefs_sysfs_init(void) -{ - int rc; - - gossip_debug(GOSSIP_SYSFS_DEBUG, "orangefs_sysfs_init: start\n"); - - /* create /sys/fs/orangefs. */ - orangefs_obj = kzalloc(sizeof(*orangefs_obj), GFP_KERNEL); - if (!orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&orangefs_obj->kobj, - &orangefs_ktype, - fs_kobj, - ORANGEFS_KOBJ_ID); - - if (rc) { - kobject_put(&orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&orangefs_obj->kobj, KOBJ_ADD); - - /* create /sys/fs/orangefs/acache. */ - acache_orangefs_obj = kzalloc(sizeof(*acache_orangefs_obj), GFP_KERNEL); - if (!acache_orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&acache_orangefs_obj->kobj, - &acache_orangefs_ktype, - &orangefs_obj->kobj, - ACACHE_KOBJ_ID); - - if (rc) { - kobject_put(&acache_orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&acache_orangefs_obj->kobj, KOBJ_ADD); - - /* create /sys/fs/orangefs/capcache. */ - capcache_orangefs_obj = - kzalloc(sizeof(*capcache_orangefs_obj), GFP_KERNEL); - if (!capcache_orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&capcache_orangefs_obj->kobj, - &capcache_orangefs_ktype, - &orangefs_obj->kobj, - CAPCACHE_KOBJ_ID); - if (rc) { - kobject_put(&capcache_orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&capcache_orangefs_obj->kobj, KOBJ_ADD); - - /* create /sys/fs/orangefs/ccache. */ - ccache_orangefs_obj = - kzalloc(sizeof(*ccache_orangefs_obj), GFP_KERNEL); - if (!ccache_orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&ccache_orangefs_obj->kobj, - &ccache_orangefs_ktype, - &orangefs_obj->kobj, - CCACHE_KOBJ_ID); - if (rc) { - kobject_put(&ccache_orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&ccache_orangefs_obj->kobj, KOBJ_ADD); - - /* create /sys/fs/orangefs/ncache. */ - ncache_orangefs_obj = kzalloc(sizeof(*ncache_orangefs_obj), GFP_KERNEL); - if (!ncache_orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&ncache_orangefs_obj->kobj, - &ncache_orangefs_ktype, - &orangefs_obj->kobj, - NCACHE_KOBJ_ID); - - if (rc) { - kobject_put(&ncache_orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&ncache_orangefs_obj->kobj, KOBJ_ADD); - - /* create /sys/fs/orangefs/perf_counters. */ - pc_orangefs_obj = kzalloc(sizeof(*pc_orangefs_obj), GFP_KERNEL); - if (!pc_orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&pc_orangefs_obj->kobj, - &pc_orangefs_ktype, - &orangefs_obj->kobj, - "perf_counters"); - - if (rc) { - kobject_put(&pc_orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&pc_orangefs_obj->kobj, KOBJ_ADD); - - /* create /sys/fs/orangefs/stats. */ - stats_orangefs_obj = kzalloc(sizeof(*stats_orangefs_obj), GFP_KERNEL); - if (!stats_orangefs_obj) { - rc = -EINVAL; - goto out; - } - - rc = kobject_init_and_add(&stats_orangefs_obj->kobj, - &stats_orangefs_ktype, - &orangefs_obj->kobj, - STATS_KOBJ_ID); - - if (rc) { - kobject_put(&stats_orangefs_obj->kobj); - rc = -EINVAL; - goto out; - } - - kobject_uevent(&stats_orangefs_obj->kobj, KOBJ_ADD); -out: - return rc; -} - -void orangefs_sysfs_exit(void) -{ - gossip_debug(GOSSIP_SYSFS_DEBUG, "orangefs_sysfs_exit: start\n"); - - kobject_put(&acache_orangefs_obj->kobj); - kobject_put(&capcache_orangefs_obj->kobj); - kobject_put(&ccache_orangefs_obj->kobj); - kobject_put(&ncache_orangefs_obj->kobj); - kobject_put(&pc_orangefs_obj->kobj); - kobject_put(&stats_orangefs_obj->kobj); - - kobject_put(&orangefs_obj->kobj); -} diff --git a/fs/orangefs/pvfs2-sysfs.h b/fs/orangefs/pvfs2-sysfs.h deleted file mode 100644 index f0b76382db02..000000000000 --- a/fs/orangefs/pvfs2-sysfs.h +++ /dev/null @@ -1,2 +0,0 @@ -extern int orangefs_sysfs_init(void); -extern void orangefs_sysfs_exit(void); diff --git a/fs/orangefs/pvfs2-utils.c b/fs/orangefs/pvfs2-utils.c deleted file mode 100644 index d132c5f712a4..000000000000 --- a/fs/orangefs/pvfs2-utils.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * (C) 2001 Clemson University and The University of Chicago - * - * See COPYING in top-level directory. - */ -#include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-dev-proto.h" -#include "pvfs2-bufmap.h" - -__s32 fsid_of_op(struct orangefs_kernel_op_s *op) -{ - __s32 fsid = ORANGEFS_FS_ID_NULL; - - if (op) { - switch (op->upcall.type) { - case ORANGEFS_VFS_OP_FILE_IO: - fsid = op->upcall.req.io.refn.fs_id; - break; - case ORANGEFS_VFS_OP_LOOKUP: - fsid = op->upcall.req.lookup.parent_refn.fs_id; - break; - case ORANGEFS_VFS_OP_CREATE: - fsid = op->upcall.req.create.parent_refn.fs_id; - break; - case ORANGEFS_VFS_OP_GETATTR: - fsid = op->upcall.req.getattr.refn.fs_id; - break; - case ORANGEFS_VFS_OP_REMOVE: - fsid = op->upcall.req.remove.parent_refn.fs_id; - break; - case ORANGEFS_VFS_OP_MKDIR: - fsid = op->upcall.req.mkdir.parent_refn.fs_id; - break; - case ORANGEFS_VFS_OP_READDIR: - fsid = op->upcall.req.readdir.refn.fs_id; - break; - case ORANGEFS_VFS_OP_SETATTR: - fsid = op->upcall.req.setattr.refn.fs_id; - break; - case ORANGEFS_VFS_OP_SYMLINK: - fsid = op->upcall.req.sym.parent_refn.fs_id; - break; - case ORANGEFS_VFS_OP_RENAME: - fsid = op->upcall.req.rename.old_parent_refn.fs_id; - break; - case ORANGEFS_VFS_OP_STATFS: - fsid = op->upcall.req.statfs.fs_id; - break; - case ORANGEFS_VFS_OP_TRUNCATE: - fsid = op->upcall.req.truncate.refn.fs_id; - break; - case ORANGEFS_VFS_OP_MMAP_RA_FLUSH: - fsid = op->upcall.req.ra_cache_flush.refn.fs_id; - break; - case ORANGEFS_VFS_OP_FS_UMOUNT: - fsid = op->upcall.req.fs_umount.fs_id; - break; - case ORANGEFS_VFS_OP_GETXATTR: - fsid = op->upcall.req.getxattr.refn.fs_id; - break; - case ORANGEFS_VFS_OP_SETXATTR: - fsid = op->upcall.req.setxattr.refn.fs_id; - break; - case ORANGEFS_VFS_OP_LISTXATTR: - fsid = op->upcall.req.listxattr.refn.fs_id; - break; - case ORANGEFS_VFS_OP_REMOVEXATTR: - fsid = op->upcall.req.removexattr.refn.fs_id; - break; - case ORANGEFS_VFS_OP_FSYNC: - fsid = op->upcall.req.fsync.refn.fs_id; - break; - default: - break; - } - } - return fsid; -} - -static void orangefs_set_inode_flags(struct inode *inode, - struct ORANGEFS_sys_attr_s *attrs) -{ - if (attrs->flags & ORANGEFS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - - if (attrs->flags & ORANGEFS_APPEND_FL) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - - if (attrs->flags & ORANGEFS_NOATIME_FL) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; - -} - -/* NOTE: symname is ignored unless the inode is a sym link */ -static int copy_attributes_to_inode(struct inode *inode, - struct ORANGEFS_sys_attr_s *attrs, - char *symname) -{ - int ret = -1; - int perm_mode = 0; - struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); - loff_t inode_size = 0; - loff_t rounded_up_size = 0; - - - /* - * arbitrarily set the inode block size; FIXME: we need to - * resolve the difference between the reported inode blocksize - * and the PAGE_CACHE_SIZE, since our block count will always - * be wrong. - * - * For now, we're setting the block count to be the proper - * number assuming the block size is 512 bytes, and the size is - * rounded up to the nearest 4K. This is apparently required - * to get proper size reports from the 'du' shell utility. - * - * changing the inode->i_blkbits to something other than - * PAGE_CACHE_SHIFT breaks mmap/execution as we depend on that. - */ - gossip_debug(GOSSIP_UTILS_DEBUG, - "attrs->mask = %x (objtype = %s)\n", - attrs->mask, - attrs->objtype == ORANGEFS_TYPE_METAFILE ? "file" : - attrs->objtype == ORANGEFS_TYPE_DIRECTORY ? "directory" : - attrs->objtype == ORANGEFS_TYPE_SYMLINK ? "symlink" : - "invalid/unknown"); - - switch (attrs->objtype) { - case ORANGEFS_TYPE_METAFILE: - orangefs_set_inode_flags(inode, attrs); - if (attrs->mask & ORANGEFS_ATTR_SYS_SIZE) { - inode_size = (loff_t) attrs->size; - rounded_up_size = - (inode_size + (4096 - (inode_size % 4096))); - - orangefs_lock_inode(inode); - inode->i_bytes = inode_size; - inode->i_blocks = - (unsigned long)(rounded_up_size / 512); - orangefs_unlock_inode(inode); - - /* - * NOTE: make sure all the places we're called - * from have the inode->i_sem lock. We're fine - * in 99% of the cases since we're mostly - * called from a lookup. - */ - inode->i_size = inode_size; - } - break; - case ORANGEFS_TYPE_SYMLINK: - if (symname != NULL) { - inode->i_size = (loff_t) strlen(symname); - break; - } - /*FALLTHRU*/ - default: - inode->i_size = PAGE_CACHE_SIZE; - - orangefs_lock_inode(inode); - inode_set_bytes(inode, inode->i_size); - orangefs_unlock_inode(inode); - break; - } - - inode->i_uid = make_kuid(&init_user_ns, attrs->owner); - inode->i_gid = make_kgid(&init_user_ns, attrs->group); - inode->i_atime.tv_sec = (time_t) attrs->atime; - inode->i_mtime.tv_sec = (time_t) attrs->mtime; - inode->i_ctime.tv_sec = (time_t) attrs->ctime; - inode->i_atime.tv_nsec = 0; - inode->i_mtime.tv_nsec = 0; - inode->i_ctime.tv_nsec = 0; - - if (attrs->perms & ORANGEFS_O_EXECUTE) - perm_mode |= S_IXOTH; - if (attrs->perms & ORANGEFS_O_WRITE) - perm_mode |= S_IWOTH; - if (attrs->perms & ORANGEFS_O_READ) - perm_mode |= S_IROTH; - - if (attrs->perms & ORANGEFS_G_EXECUTE) - perm_mode |= S_IXGRP; - if (attrs->perms & ORANGEFS_G_WRITE) - perm_mode |= S_IWGRP; - if (attrs->perms & ORANGEFS_G_READ) - perm_mode |= S_IRGRP; - - if (attrs->perms & ORANGEFS_U_EXECUTE) - perm_mode |= S_IXUSR; - if (attrs->perms & ORANGEFS_U_WRITE) - perm_mode |= S_IWUSR; - if (attrs->perms & ORANGEFS_U_READ) - perm_mode |= S_IRUSR; - - if (attrs->perms & ORANGEFS_G_SGID) - perm_mode |= S_ISGID; - if (attrs->perms & ORANGEFS_U_SUID) - perm_mode |= S_ISUID; - - inode->i_mode = perm_mode; - - if (is_root_handle(inode)) { - /* special case: mark the root inode as sticky */ - inode->i_mode |= S_ISVTX; - gossip_debug(GOSSIP_UTILS_DEBUG, - "Marking inode %pU as sticky\n", - get_khandle_from_ino(inode)); - } - - switch (attrs->objtype) { - case ORANGEFS_TYPE_METAFILE: - inode->i_mode |= S_IFREG; - ret = 0; - break; - case ORANGEFS_TYPE_DIRECTORY: - inode->i_mode |= S_IFDIR; - /* NOTE: we have no good way to keep nlink consistent - * for directories across clients; keep constant at 1. - * Why 1? If we go with 2, then find(1) gets confused - * and won't work properly withouth the -noleaf option - */ - set_nlink(inode, 1); - ret = 0; - break; - case ORANGEFS_TYPE_SYMLINK: - inode->i_mode |= S_IFLNK; - - /* copy link target to inode private data */ - if (orangefs_inode && symname) { - strncpy(orangefs_inode->link_target, - symname, - ORANGEFS_NAME_MAX); - gossip_debug(GOSSIP_UTILS_DEBUG, - "Copied attr link target %s\n", - orangefs_inode->link_target); - } - gossip_debug(GOSSIP_UTILS_DEBUG, - "symlink mode %o\n", - inode->i_mode); - ret = 0; - break; - default: - gossip_err("orangefs: copy_attributes_to_inode: got invalid attribute type %x\n", - attrs->objtype); - } - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs: copy_attributes_to_inode: setting i_mode to %o, i_size to %lu\n", - inode->i_mode, - (unsigned long)i_size_read(inode)); - - return ret; -} - -/* - * NOTE: in kernel land, we never use the sys_attr->link_target for - * anything, so don't bother copying it into the sys_attr object here. - */ -static inline int copy_attributes_from_inode(struct inode *inode, - struct ORANGEFS_sys_attr_s *attrs, - struct iattr *iattr) -{ - umode_t tmp_mode; - - if (!iattr || !inode || !attrs) { - gossip_err("NULL iattr (%p), inode (%p), attrs (%p) " - "in copy_attributes_from_inode!\n", - iattr, - inode, - attrs); - return -EINVAL; - } - /* - * We need to be careful to only copy the attributes out of the - * iattr object that we know are valid. - */ - attrs->mask = 0; - if (iattr->ia_valid & ATTR_UID) { - attrs->owner = from_kuid(current_user_ns(), iattr->ia_uid); - attrs->mask |= ORANGEFS_ATTR_SYS_UID; - gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner); - } - if (iattr->ia_valid & ATTR_GID) { - attrs->group = from_kgid(current_user_ns(), iattr->ia_gid); - attrs->mask |= ORANGEFS_ATTR_SYS_GID; - gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group); - } - - if (iattr->ia_valid & ATTR_ATIME) { - attrs->mask |= ORANGEFS_ATTR_SYS_ATIME; - if (iattr->ia_valid & ATTR_ATIME_SET) { - attrs->atime = - orangefs_convert_time_field(&iattr->ia_atime); - attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET; - } - } - if (iattr->ia_valid & ATTR_MTIME) { - attrs->mask |= ORANGEFS_ATTR_SYS_MTIME; - if (iattr->ia_valid & ATTR_MTIME_SET) { - attrs->mtime = - orangefs_convert_time_field(&iattr->ia_mtime); - attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET; - } - } - if (iattr->ia_valid & ATTR_CTIME) - attrs->mask |= ORANGEFS_ATTR_SYS_CTIME; - - /* - * ORANGEFS cannot set size with a setattr operation. Probably not likely - * to be requested through the VFS, but just in case, don't worry about - * ATTR_SIZE - */ - - if (iattr->ia_valid & ATTR_MODE) { - tmp_mode = iattr->ia_mode; - if (tmp_mode & (S_ISVTX)) { - if (is_root_handle(inode)) { - /* - * allow sticky bit to be set on root (since - * it shows up that way by default anyhow), - * but don't show it to the server - */ - tmp_mode -= S_ISVTX; - } else { - gossip_debug(GOSSIP_UTILS_DEBUG, - "User attempted to set sticky bit on non-root directory; returning EINVAL.\n"); - return -EINVAL; - } - } - - if (tmp_mode & (S_ISUID)) { - gossip_debug(GOSSIP_UTILS_DEBUG, - "Attempting to set setuid bit (not supported); returning EINVAL.\n"); - return -EINVAL; - } - - attrs->perms = ORANGEFS_util_translate_mode(tmp_mode); - attrs->mask |= ORANGEFS_ATTR_SYS_PERM; - } - - return 0; -} - -/* - * issues a orangefs getattr request and fills in the appropriate inode - * attributes if successful. returns 0 on success; -errno otherwise - */ -int orangefs_inode_getattr(struct inode *inode, __u32 getattr_mask) -{ - struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); - struct orangefs_kernel_op_s *new_op; - int ret = -EINVAL; - - gossip_debug(GOSSIP_UTILS_DEBUG, - "%s: called on inode %pU\n", - __func__, - get_khandle_from_ino(inode)); - - new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR); - if (!new_op) - return -ENOMEM; - new_op->upcall.req.getattr.refn = orangefs_inode->refn; - new_op->upcall.req.getattr.mask = getattr_mask; - - ret = service_operation(new_op, __func__, - get_interruptible_flag(inode)); - if (ret != 0) - goto out; - - if (copy_attributes_to_inode(inode, - &new_op->downcall.resp.getattr.attributes, - new_op->downcall.resp.getattr.link_target)) { - gossip_err("%s: failed to copy attributes\n", __func__); - ret = -ENOENT; - goto out; - } - - /* - * Store blksize in orangefs specific part of inode structure; we are - * only going to use this to report to stat to make sure it doesn't - * perturb any inode related code paths. - */ - if (new_op->downcall.resp.getattr.attributes.objtype == - ORANGEFS_TYPE_METAFILE) { - orangefs_inode->blksize = - new_op->downcall.resp.getattr.attributes.blksize; - } else { - /* mimic behavior of generic_fillattr() for other types. */ - orangefs_inode->blksize = (1 << inode->i_blkbits); - - } - -out: - gossip_debug(GOSSIP_UTILS_DEBUG, - "Getattr on handle %pU, " - "fsid %d\n (inode ct = %d) returned %d\n", - &orangefs_inode->refn.khandle, - orangefs_inode->refn.fs_id, - (int)atomic_read(&inode->i_count), - ret); - - op_release(new_op); - return ret; -} - -/* - * issues a orangefs setattr request to make sure the new attribute values - * take effect if successful. returns 0 on success; -errno otherwise - */ -int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr) -{ - struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); - struct orangefs_kernel_op_s *new_op; - int ret; - - new_op = op_alloc(ORANGEFS_VFS_OP_SETATTR); - if (!new_op) - return -ENOMEM; - - new_op->upcall.req.setattr.refn = orangefs_inode->refn; - ret = copy_attributes_from_inode(inode, - &new_op->upcall.req.setattr.attributes, - iattr); - if (ret < 0) { - op_release(new_op); - return ret; - } - - ret = service_operation(new_op, __func__, - get_interruptible_flag(inode)); - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_inode_setattr: returning %d\n", - ret); - - /* when request is serviced properly, free req op struct */ - op_release(new_op); - - /* - * successful setattr should clear the atime, mtime and - * ctime flags. - */ - if (ret == 0) { - ClearAtimeFlag(orangefs_inode); - ClearMtimeFlag(orangefs_inode); - ClearCtimeFlag(orangefs_inode); - ClearModeFlag(orangefs_inode); - } - - return ret; -} - -int orangefs_flush_inode(struct inode *inode) -{ - /* - * If it is a dirty inode, this function gets called. - * Gather all the information that needs to be setattr'ed - * Right now, this will only be used for mode, atime, mtime - * and/or ctime. - */ - struct iattr wbattr; - int ret; - int mtime_flag; - int ctime_flag; - int atime_flag; - int mode_flag; - struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); - - memset(&wbattr, 0, sizeof(wbattr)); - - /* - * check inode flags up front, and clear them if they are set. This - * will prevent multiple processes from all trying to flush the same - * inode if they call close() simultaneously - */ - mtime_flag = MtimeFlag(orangefs_inode); - ClearMtimeFlag(orangefs_inode); - ctime_flag = CtimeFlag(orangefs_inode); - ClearCtimeFlag(orangefs_inode); - atime_flag = AtimeFlag(orangefs_inode); - ClearAtimeFlag(orangefs_inode); - mode_flag = ModeFlag(orangefs_inode); - ClearModeFlag(orangefs_inode); - - /* -- Lazy atime,mtime and ctime update -- - * Note: all times are dictated by server in the new scheme - * and not by the clients - * - * Also mode updates are being handled now.. - */ - - if (mtime_flag) - wbattr.ia_valid |= ATTR_MTIME; - if (ctime_flag) - wbattr.ia_valid |= ATTR_CTIME; - if (atime_flag) - wbattr.ia_valid |= ATTR_ATIME; - - if (mode_flag) { - wbattr.ia_mode = inode->i_mode; - wbattr.ia_valid |= ATTR_MODE; - } - - gossip_debug(GOSSIP_UTILS_DEBUG, - "*********** orangefs_flush_inode: %pU " - "(ia_valid %d)\n", - get_khandle_from_ino(inode), - wbattr.ia_valid); - if (wbattr.ia_valid == 0) { - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_flush_inode skipping setattr()\n"); - return 0; - } - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_flush_inode (%pU) writing mode %o\n", - get_khandle_from_ino(inode), - inode->i_mode); - - ret = orangefs_inode_setattr(inode, &wbattr); - - return ret; -} - -int orangefs_unmount_sb(struct super_block *sb) -{ - int ret = -EINVAL; - struct orangefs_kernel_op_s *new_op = NULL; - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_unmount_sb called on sb %p\n", - sb); - - new_op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT); - if (!new_op) - return -ENOMEM; - new_op->upcall.req.fs_umount.id = ORANGEFS_SB(sb)->id; - new_op->upcall.req.fs_umount.fs_id = ORANGEFS_SB(sb)->fs_id; - strncpy(new_op->upcall.req.fs_umount.orangefs_config_server, - ORANGEFS_SB(sb)->devname, - ORANGEFS_MAX_SERVER_ADDR_LEN); - - gossip_debug(GOSSIP_UTILS_DEBUG, - "Attempting ORANGEFS Unmount via host %s\n", - new_op->upcall.req.fs_umount.orangefs_config_server); - - ret = service_operation(new_op, "orangefs_fs_umount", 0); - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_unmount: got return value of %d\n", ret); - if (ret) - sb = ERR_PTR(ret); - else - ORANGEFS_SB(sb)->mount_pending = 1; - - op_release(new_op); - return ret; -} - -/* - * NOTE: on successful cancellation, be sure to return -EINTR, as - * that's the return value the caller expects - */ -int orangefs_cancel_op_in_progress(__u64 tag) -{ - int ret = -EINVAL; - struct orangefs_kernel_op_s *new_op = NULL; - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_cancel_op_in_progress called on tag %llu\n", - llu(tag)); - - new_op = op_alloc(ORANGEFS_VFS_OP_CANCEL); - if (!new_op) - return -ENOMEM; - new_op->upcall.req.cancel.op_tag = tag; - - gossip_debug(GOSSIP_UTILS_DEBUG, - "Attempting ORANGEFS operation cancellation of tag %llu\n", - llu(new_op->upcall.req.cancel.op_tag)); - - ret = service_operation(new_op, "orangefs_cancel", ORANGEFS_OP_CANCELLATION); - - gossip_debug(GOSSIP_UTILS_DEBUG, - "orangefs_cancel_op_in_progress: got return value of %d\n", - ret); - - op_release(new_op); - return ret; -} - -void orangefs_op_initialize(struct orangefs_kernel_op_s *op) -{ - if (op) { - spin_lock(&op->lock); - op->io_completed = 0; - - op->upcall.type = ORANGEFS_VFS_OP_INVALID; - op->downcall.type = ORANGEFS_VFS_OP_INVALID; - op->downcall.status = -1; - - op->op_state = OP_VFS_STATE_UNKNOWN; - op->tag = 0; - spin_unlock(&op->lock); - } -} - -void orangefs_make_bad_inode(struct inode *inode) -{ - if (is_root_handle(inode)) { - /* - * if this occurs, the pvfs2-client-core was killed but we - * can't afford to lose the inode operations and such - * associated with the root handle in any case. - */ - gossip_debug(GOSSIP_UTILS_DEBUG, - "*** NOT making bad root inode %pU\n", - get_khandle_from_ino(inode)); - } else { - gossip_debug(GOSSIP_UTILS_DEBUG, - "*** making bad inode %pU\n", - get_khandle_from_ino(inode)); - make_bad_inode(inode); - } -} - -/* Block all blockable signals... */ -void block_signals(sigset_t *orig_sigset) -{ - sigset_t mask; - - /* - * Initialize all entries in the signal set to the - * inverse of the given mask. - */ - siginitsetinv(&mask, sigmask(SIGKILL)); - - /* Block 'em Danno... */ - sigprocmask(SIG_BLOCK, &mask, orig_sigset); -} - -/* set the signal mask to the given template... */ -void set_signals(sigset_t *sigset) -{ - sigprocmask(SIG_SETMASK, sigset, NULL); -} - -/* - * The following is a very dirty hack that is now a permanent part of the - * ORANGEFS protocol. See protocol.h for more error definitions. - */ - -/* The order matches include/orangefs-types.h in the OrangeFS source. */ -static int PINT_errno_mapping[] = { - 0, EPERM, ENOENT, EINTR, EIO, ENXIO, EBADF, EAGAIN, ENOMEM, - EFAULT, EBUSY, EEXIST, ENODEV, ENOTDIR, EISDIR, EINVAL, EMFILE, - EFBIG, ENOSPC, EROFS, EMLINK, EPIPE, EDEADLK, ENAMETOOLONG, - ENOLCK, ENOSYS, ENOTEMPTY, ELOOP, EWOULDBLOCK, ENOMSG, EUNATCH, - EBADR, EDEADLOCK, ENODATA, ETIME, ENONET, EREMOTE, ECOMM, - EPROTO, EBADMSG, EOVERFLOW, ERESTART, EMSGSIZE, EPROTOTYPE, - ENOPROTOOPT, EPROTONOSUPPORT, EOPNOTSUPP, EADDRINUSE, - EADDRNOTAVAIL, ENETDOWN, ENETUNREACH, ENETRESET, ENOBUFS, - ETIMEDOUT, ECONNREFUSED, EHOSTDOWN, EHOSTUNREACH, EALREADY, - EACCES, ECONNRESET, ERANGE -}; - -int orangefs_normalize_to_errno(__s32 error_code) -{ - __u32 i; - - /* Success */ - if (error_code == 0) { - return 0; - /* - * This shouldn't ever happen. If it does it should be fixed on the - * server. - */ - } else if (error_code > 0) { - gossip_err("orangefs: error status receieved.\n"); - gossip_err("orangefs: assuming error code is inverted.\n"); - error_code = -error_code; - } - - /* - * XXX: This is very bad since error codes from ORANGEFS may not be - * suitable for return into userspace. - */ - - /* - * Convert ORANGEFS error values into errno values suitable for return - * from the kernel. - */ - if ((-error_code) & ORANGEFS_NON_ERRNO_ERROR_BIT) { - if (((-error_code) & - (ORANGEFS_ERROR_NUMBER_BITS|ORANGEFS_NON_ERRNO_ERROR_BIT| - ORANGEFS_ERROR_BIT)) == ORANGEFS_ECANCEL) { - /* - * cancellation error codes generally correspond to - * a timeout from the client's perspective - */ - error_code = -ETIMEDOUT; - } else { - /* assume a default error code */ - gossip_err("orangefs: warning: got error code without errno equivalent: %d.\n", error_code); - error_code = -EINVAL; - } - - /* Convert ORANGEFS encoded errno values into regular errno values. */ - } else if ((-error_code) & ORANGEFS_ERROR_BIT) { - i = (-error_code) & ~(ORANGEFS_ERROR_BIT|ORANGEFS_ERROR_CLASS_BITS); - if (i < sizeof(PINT_errno_mapping)/sizeof(*PINT_errno_mapping)) - error_code = -PINT_errno_mapping[i]; - else - error_code = -EINVAL; - - /* - * Only ORANGEFS protocol error codes should ever come here. Otherwise - * there is a bug somewhere. - */ - } else { - gossip_err("orangefs: orangefs_normalize_to_errno: got error code which is not from ORANGEFS.\n"); - } - return error_code; -} - -#define NUM_MODES 11 -__s32 ORANGEFS_util_translate_mode(int mode) -{ - int ret = 0; - int i = 0; - static int modes[NUM_MODES] = { - S_IXOTH, S_IWOTH, S_IROTH, - S_IXGRP, S_IWGRP, S_IRGRP, - S_IXUSR, S_IWUSR, S_IRUSR, - S_ISGID, S_ISUID - }; - static int orangefs_modes[NUM_MODES] = { - ORANGEFS_O_EXECUTE, ORANGEFS_O_WRITE, ORANGEFS_O_READ, - ORANGEFS_G_EXECUTE, ORANGEFS_G_WRITE, ORANGEFS_G_READ, - ORANGEFS_U_EXECUTE, ORANGEFS_U_WRITE, ORANGEFS_U_READ, - ORANGEFS_G_SGID, ORANGEFS_U_SUID - }; - - for (i = 0; i < NUM_MODES; i++) - if (mode & modes[i]) - ret |= orangefs_modes[i]; - - return ret; -} -#undef NUM_MODES - -/* - * After obtaining a string representation of the client's debug - * keywords and their associated masks, this function is called to build an - * array of these values. - */ -int orangefs_prepare_cdm_array(char *debug_array_string) -{ - int i; - int rc = -EINVAL; - char *cds_head = NULL; - char *cds_delimiter = NULL; - int keyword_len = 0; - - gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); - - /* - * figure out how many elements the cdm_array needs. - */ - for (i = 0; i < strlen(debug_array_string); i++) - if (debug_array_string[i] == '\n') - cdm_element_count++; - - if (!cdm_element_count) { - pr_info("No elements in client debug array string!\n"); - goto out; - } - - cdm_array = - kzalloc(cdm_element_count * sizeof(struct client_debug_mask), - GFP_KERNEL); - if (!cdm_array) { - pr_info("malloc failed for cdm_array!\n"); - rc = -ENOMEM; - goto out; - } - - cds_head = debug_array_string; - - for (i = 0; i < cdm_element_count; i++) { - cds_delimiter = strchr(cds_head, '\n'); - *cds_delimiter = '\0'; - - keyword_len = strcspn(cds_head, " "); - - cdm_array[i].keyword = kzalloc(keyword_len + 1, GFP_KERNEL); - if (!cdm_array[i].keyword) { - rc = -ENOMEM; - goto out; - } - - sscanf(cds_head, - "%s %llx %llx", - cdm_array[i].keyword, - (unsigned long long *)&(cdm_array[i].mask1), - (unsigned long long *)&(cdm_array[i].mask2)); - - if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE)) - client_verbose_index = i; - - if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL)) - client_all_index = i; - - cds_head = cds_delimiter + 1; - } - - rc = cdm_element_count; - - gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n", __func__, rc); - -out: - - return rc; - -} - -/* - * /sys/kernel/debug/orangefs/debug-help can be catted to - * see all the available kernel and client debug keywords. - * - * When the kernel boots, we have no idea what keywords the - * client supports, nor their associated masks. - * - * We pass through this function once at boot and stamp a - * boilerplate "we don't know" message for the client in the - * debug-help file. We pass through here again when the client - * starts and then we can fill out the debug-help file fully. - * - * The client might be restarted any number of times between - * reboots, we only build the debug-help file the first time. - */ -int orangefs_prepare_debugfs_help_string(int at_boot) -{ - int rc = -EINVAL; - int i; - int byte_count = 0; - char *client_title = "Client Debug Keywords:\n"; - char *kernel_title = "Kernel Debug Keywords:\n"; - - gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); - - if (at_boot) { - byte_count += strlen(HELP_STRING_UNINITIALIZED); - client_title = HELP_STRING_UNINITIALIZED; - } else { - /* - * fill the client keyword/mask array and remember - * how many elements there were. - */ - cdm_element_count = - orangefs_prepare_cdm_array(client_debug_array_string); - if (cdm_element_count <= 0) - goto out; - - /* Count the bytes destined for debug_help_string. */ - byte_count += strlen(client_title); - - for (i = 0; i < cdm_element_count; i++) { - byte_count += strlen(cdm_array[i].keyword + 2); - if (byte_count >= DEBUG_HELP_STRING_SIZE) { - pr_info("%s: overflow 1!\n", __func__); - goto out; - } - } - - gossip_debug(GOSSIP_UTILS_DEBUG, - "%s: cdm_element_count:%d:\n", - __func__, - cdm_element_count); - } - - byte_count += strlen(kernel_title); - for (i = 0; i < num_kmod_keyword_mask_map; i++) { - byte_count += - strlen(s_kmod_keyword_mask_map[i].keyword + 2); - if (byte_count >= DEBUG_HELP_STRING_SIZE) { - pr_info("%s: overflow 2!\n", __func__); - goto out; - } - } - - /* build debug_help_string. */ - debug_help_string = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL); - if (!debug_help_string) { - rc = -ENOMEM; - goto out; - } - - strcat(debug_help_string, client_title); - - if (!at_boot) { - for (i = 0; i < cdm_element_count; i++) { - strcat(debug_help_string, "\t"); - strcat(debug_help_string, cdm_array[i].keyword); - strcat(debug_help_string, "\n"); - } - } - - strcat(debug_help_string, "\n"); - strcat(debug_help_string, kernel_title); - - for (i = 0; i < num_kmod_keyword_mask_map; i++) { - strcat(debug_help_string, "\t"); - strcat(debug_help_string, s_kmod_keyword_mask_map[i].keyword); - strcat(debug_help_string, "\n"); - } - - rc = 0; - -out: - - return rc; - -} - -/* - * kernel = type 0 - * client = type 1 - */ -void debug_mask_to_string(void *mask, int type) -{ - int i; - int len = 0; - char *debug_string; - int element_count = 0; - - gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); - - if (type) { - debug_string = client_debug_string; - element_count = cdm_element_count; - } else { - debug_string = kernel_debug_string; - element_count = num_kmod_keyword_mask_map; - } - - memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); - - /* - * Some keywords, like "all" or "verbose", are amalgams of - * numerous other keywords. Make a special check for those - * before grinding through the whole mask only to find out - * later... - */ - if (check_amalgam_keyword(mask, type)) - goto out; - - /* Build the debug string. */ - for (i = 0; i < element_count; i++) - if (type) - do_c_string(mask, i); - else - do_k_string(mask, i); - - len = strlen(debug_string); - - if ((len) && (type)) - client_debug_string[len - 1] = '\0'; - else if (len) - kernel_debug_string[len - 1] = '\0'; - else if (type) - strcpy(client_debug_string, "none"); - else - strcpy(kernel_debug_string, "none"); - -out: -gossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n", __func__, debug_string); - - return; - -} - -void do_k_string(void *k_mask, int index) -{ - __u64 *mask = (__u64 *) k_mask; - - if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword)) - goto out; - - if (*mask & s_kmod_keyword_mask_map[index].mask_val) { - if ((strlen(kernel_debug_string) + - strlen(s_kmod_keyword_mask_map[index].keyword)) - < ORANGEFS_MAX_DEBUG_STRING_LEN - 1) { - strcat(kernel_debug_string, - s_kmod_keyword_mask_map[index].keyword); - strcat(kernel_debug_string, ","); - } else { - gossip_err("%s: overflow!\n", __func__); - strcpy(kernel_debug_string, ORANGEFS_ALL); - goto out; - } - } - -out: - - return; -} - -void do_c_string(void *c_mask, int index) -{ - struct client_debug_mask *mask = (struct client_debug_mask *) c_mask; - - if (keyword_is_amalgam(cdm_array[index].keyword)) - goto out; - - if ((mask->mask1 & cdm_array[index].mask1) || - (mask->mask2 & cdm_array[index].mask2)) { - if ((strlen(client_debug_string) + - strlen(cdm_array[index].keyword) + 1) - < ORANGEFS_MAX_DEBUG_STRING_LEN - 2) { - strcat(client_debug_string, - cdm_array[index].keyword); - strcat(client_debug_string, ","); - } else { - gossip_err("%s: overflow!\n", __func__); - strcpy(client_debug_string, ORANGEFS_ALL); - goto out; - } - } -out: - return; -} - -int keyword_is_amalgam(char *keyword) -{ - int rc = 0; - - if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE))) - rc = 1; - - return rc; -} - -/* - * kernel = type 0 - * client = type 1 - * - * return 1 if we found an amalgam. - */ -int check_amalgam_keyword(void *mask, int type) -{ - __u64 *k_mask; - struct client_debug_mask *c_mask; - int k_all_index = num_kmod_keyword_mask_map - 1; - int rc = 0; - - if (type) { - c_mask = (struct client_debug_mask *) mask; - - if ((c_mask->mask1 == cdm_array[client_all_index].mask1) && - (c_mask->mask2 == cdm_array[client_all_index].mask2)) { - strcpy(client_debug_string, ORANGEFS_ALL); - rc = 1; - goto out; - } - - if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) && - (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) { - strcpy(client_debug_string, ORANGEFS_VERBOSE); - rc = 1; - goto out; - } - - } else { - k_mask = (__u64 *) mask; - - if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) { - strcpy(kernel_debug_string, ORANGEFS_ALL); - rc = 1; - goto out; - } - } - -out: - - return rc; -} - -/* - * kernel = type 0 - * client = type 1 - */ -void debug_string_to_mask(char *debug_string, void *mask, int type) -{ - char *unchecked_keyword; - int i; - char *strsep_fodder = kstrdup(debug_string, GFP_KERNEL); - char *original_pointer; - int element_count = 0; - struct client_debug_mask *c_mask; - __u64 *k_mask; - - gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); - - if (type) { - c_mask = (struct client_debug_mask *)mask; - element_count = cdm_element_count; - } else { - k_mask = (__u64 *)mask; - *k_mask = 0; - element_count = num_kmod_keyword_mask_map; - } - - original_pointer = strsep_fodder; - while ((unchecked_keyword = strsep(&strsep_fodder, ","))) - if (strlen(unchecked_keyword)) { - for (i = 0; i < element_count; i++) - if (type) - do_c_mask(i, - unchecked_keyword, - &c_mask); - else - do_k_mask(i, - unchecked_keyword, - &k_mask); - } - - kfree(original_pointer); -} - -void do_c_mask(int i, - char *unchecked_keyword, - struct client_debug_mask **sane_mask) -{ - - if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) { - (**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1; - (**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2; - } -} - -void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask) -{ - - if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword)) - **sane_mask = (**sane_mask) | - s_kmod_keyword_mask_map[i].mask_val; -} diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index c104de1ae5de..52bc522ea21c 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -5,8 +5,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" #include diff --git a/fs/orangefs/symlink.c b/fs/orangefs/symlink.c index 321f626b190b..1b3ae63463dc 100644 --- a/fs/orangefs/symlink.c +++ b/fs/orangefs/symlink.c @@ -5,8 +5,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" static const char *orangefs_follow_link(struct dentry *dentry, void **cookie) { diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c index cfc8dc59c4eb..c731cbdd5fbd 100644 --- a/fs/orangefs/waitqueue.c +++ b/fs/orangefs/waitqueue.c @@ -13,8 +13,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" /* * What we do in this function is to walk the list of operations that are diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c index aeb3c3083591..0e4e01602738 100644 --- a/fs/orangefs/xattr.c +++ b/fs/orangefs/xattr.c @@ -9,8 +9,8 @@ */ #include "protocol.h" -#include "pvfs2-kernel.h" -#include "pvfs2-bufmap.h" +#include "orangefs-kernel.h" +#include "orangefs-bufmap.h" #include #include -- cgit v1.2.3