lprocfs_status.c

来自「lustre 1.6.5 source code」· C语言 代码 · 共 1,933 行 · 第 1/5 页

C
1,933
字号
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * *  Copyright (C) 2002, 2003 Cluster File Systems, Inc. *   Author: Hariharan Thantry <thantry@users.sourceforge.net> * *   This file is part of the Lustre file system, http://www.lustre.org *   Lustre is a trademark of Cluster File Systems, Inc. * *   You may have signed or agreed to another license before downloading *   this software.  If so, you are bound by the terms and conditions *   of that agreement, and the following does not apply to you.  See the *   LICENSE file included with this distribution for more information. * *   If you did not agree to a different license, then this copy of Lustre *   is open source software; you can redistribute it and/or modify it *   under the terms of version 2 of the GNU General Public License as *   published by the Free Software Foundation. * *   In either case, Lustre is distributed in the hope that it will be *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   license text for more details. */#ifndef EXPORT_SYMTAB# define EXPORT_SYMTAB#endif#define DEBUG_SUBSYSTEM S_CLASS#ifndef __KERNEL__# include <liblustre.h>#endif#include <obd_class.h>#include <lprocfs_status.h>#include <lustre_fsfilt.h>#if defined(LPROCFS)#define MAX_STRING_SIZE 128/* for bug 10866, global variable */DECLARE_RWSEM(_lprocfs_lock);EXPORT_SYMBOL(_lprocfs_lock);int lprocfs_seq_release(struct inode *inode, struct file *file){        LPROCFS_EXIT();        return seq_release(inode, file);}EXPORT_SYMBOL(lprocfs_seq_release);struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,                                    const char *name){        struct proc_dir_entry *temp;        if (head == NULL)                return NULL;        LPROCFS_ENTRY();        temp = head->subdir;        while (temp != NULL) {                if (strcmp(temp->name, name) == 0) {                        LPROCFS_EXIT();                        return temp;                }                temp = temp->next;        }        LPROCFS_ENTRY();        return NULL;}/* lprocfs API calls *//* Function that emulates snprintf but also has the side effect of advancing   the page pointer for the next write into the buffer, incrementing the total   length written to the buffer, and decrementing the size left in the   buffer. */static int lprocfs_obd_snprintf(char **page, int end, int *len,                                const char *format, ...){        va_list list;        int n;        if (*len >= end)                return 0;        va_start(list, format);        n = vsnprintf(*page, end - *len, format, list);        va_end(list);        *page += n; *len += n;        return n;}int lprocfs_add_simple(struct proc_dir_entry *root, char *name,                       read_proc_t *read_proc, write_proc_t *write_proc,                       void *data){        struct proc_dir_entry *proc;        mode_t mode = 0;                if (root == NULL || name == NULL)                return -EINVAL;        if (read_proc)                mode = 0444;        if (write_proc)                mode |= 0200;        proc = create_proc_entry(name, mode, root);        if (!proc) {                CERROR("LprocFS: No memory to create /proc entry %s", name);                return -ENOMEM;        }        proc->read_proc = read_proc;        proc->write_proc = write_proc;        proc->data = data;        return 0;}static ssize_t lprocfs_fops_read(struct file *f, char __user *buf, size_t size, loff_t *ppos){        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);        char *page, *start = NULL;        int rc = 0, eof = 1, count;        if (*ppos >= PAGE_SIZE)                return 0;        page = (char *)__get_free_page(GFP_KERNEL);        if (page == NULL)                return -ENOMEM;        LPROCFS_ENTRY();        OBD_FAIL_TIMEOUT(OBD_FAIL_LPROC_REMOVE, 10);        if (!dp->deleted && dp->read_proc)                rc = dp->read_proc(page, &start, *ppos, PAGE_SIZE,                         &eof, dp->data);        LPROCFS_EXIT();        if (rc <= 0)                goto out;        /* for lustre proc read, the read count must be less than PAGE_SIZE */        LASSERT(eof == 1);        if (start == NULL) {                rc -= *ppos;                if (rc < 0)                        rc = 0;                if (rc == 0)                        goto out;                start = page + *ppos;        } else if (start < page) {                start = page;        }        count = (rc < size) ? rc : size;        if (copy_to_user(buf, start, count)) {                rc = -EFAULT;                goto out;        }        *ppos += count;out:        free_page((unsigned long)page);        return rc;}static ssize_t lprocfs_fops_write(struct file *f, const char __user *buf, size_t size, loff_t *ppos){        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);        int rc = -EIO;        LPROCFS_ENTRY();        if (!dp->deleted && dp->write_proc)                rc = dp->write_proc(f, buf, size, dp->data);        LPROCFS_EXIT();        return rc;}static struct file_operations lprocfs_generic_fops = {        .owner = THIS_MODULE,        .read = lprocfs_fops_read,        .write = lprocfs_fops_write,};int lprocfs_evict_client_open(struct inode *inode, struct file *f){        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);        struct obd_device *obd = dp->data;        atomic_inc(&obd->obd_evict_inprogress);        return 0;}int lprocfs_evict_client_release(struct inode *inode, struct file *f){        struct proc_dir_entry *dp = PDE(f->f_dentry->d_inode);        struct obd_device *obd = dp->data;        atomic_dec(&obd->obd_evict_inprogress);        wake_up(&obd->obd_evict_inprogress_waitq);        LPROCFS_EXIT();        return 0;}struct file_operations lprocfs_evict_client_fops = {        .owner = THIS_MODULE,        .read = lprocfs_fops_read,        .write = lprocfs_fops_write,        .open = lprocfs_evict_client_open,        .release = lprocfs_evict_client_release,};EXPORT_SYMBOL(lprocfs_evict_client_fops);int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,                     void *data){        if (root == NULL || list == NULL)                return -EINVAL;        while (list->name != NULL) {                struct proc_dir_entry *cur_root, *proc;                char *pathcopy, *cur, *next, pathbuf[64];                int pathsize = strlen(list->name) + 1;                proc = NULL;                cur_root = root;                /* need copy of path for strsep */                if (strlen(list->name) > sizeof(pathbuf) - 1) {                        OBD_ALLOC(pathcopy, pathsize);                        if (pathcopy == NULL)                                return -ENOMEM;                } else {                        pathcopy = pathbuf;                }                next = pathcopy;                strcpy(pathcopy, list->name);                while (cur_root != NULL && (cur = strsep(&next, "/"))) {                        if (*cur =='\0') /* skip double/trailing "/" */                                continue;                        proc = lprocfs_srch(cur_root, cur);                        CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",                               cur_root->name, cur, next,                               (proc ? "exists" : "new"));                        if (next != NULL) {                                cur_root = (proc ? proc :                                            proc_mkdir(cur, cur_root));                        } else if (proc == NULL) {                                mode_t mode = 0;                                if (list->read_fptr)                                        mode = 0444;                                if (list->write_fptr)                                        mode |= 0200;                                proc = create_proc_entry(cur, mode, cur_root);                        }                }                if (pathcopy != pathbuf)                        OBD_FREE(pathcopy, pathsize);                if (cur_root == NULL || proc == NULL) {                        CERROR("LprocFS: No memory to create /proc entry %s",                               list->name);                        return -ENOMEM;                }                if (list->fops)                        proc->proc_fops = list->fops;                else                        proc->proc_fops = &lprocfs_generic_fops;                proc->read_proc = list->read_fptr;                proc->write_proc = list->write_fptr;                proc->data = (list->data ? list->data : data);                list++;        }        return 0;}void lprocfs_remove(struct proc_dir_entry **rooth){        struct proc_dir_entry *root = *rooth;        struct proc_dir_entry *temp = root;        struct proc_dir_entry *rm_entry;        struct proc_dir_entry *parent;        if (!root)                return;        *rooth = NULL;        parent = root->parent;        LASSERT(parent != NULL);        LPROCFS_ENTRY(); /* search vs remove race */        while (1) {                while (temp->subdir != NULL)                        temp = temp->subdir;                rm_entry = temp;                temp = temp->parent;                /* Memory corruption once caused this to fail, and                   without this LASSERT we would loop here forever. */                LASSERTF(strlen(rm_entry->name) == rm_entry->namelen,                         "0x%p  %s/%s len %d\n", rm_entry, temp->name,                         rm_entry->name, (int)strlen(rm_entry->name));                /* Now, the rm_entry->deleted flags is protected                  * by _lprocfs_lock. */                rm_entry->data = NULL;                remove_proc_entry(rm_entry->name, temp);                if (temp == parent)                        break;        }        LPROCFS_EXIT();}struct proc_dir_entry *lprocfs_register(const char *name,                                        struct proc_dir_entry *parent,                                        struct lprocfs_vars *list, void *data){        struct proc_dir_entry *newchild;        newchild = lprocfs_srch(parent, name);        if (newchild != NULL) {                CERROR(" Lproc: Attempting to register %s more than once \n",                       name);                return ERR_PTR(-EALREADY);        }        newchild = proc_mkdir(name, parent);        if (newchild != NULL && list != NULL) {                int rc = lprocfs_add_vars(newchild, list, data);                if (rc) {                        lprocfs_remove(&newchild);                        return ERR_PTR(rc);                }        }        return newchild;}/* Generic callbacks */int lprocfs_rd_uint(char *page, char **start, off_t off,                    int count, int *eof, void *data){        unsigned int *temp = (unsigned int *)data;        return snprintf(page, count, "%u\n", *temp);}int lprocfs_wr_uint(struct file *file, const char *buffer,                    unsigned long count, void *data){        unsigned *p = data;        char dummy[MAX_STRING_SIZE + 1], *end;        unsigned long tmp;        dummy[MAX_STRING_SIZE] = '\0';        if (copy_from_user(dummy, buffer, MAX_STRING_SIZE))                return -EFAULT;        tmp = simple_strtoul(dummy, &end, 0);        if (dummy == end)                return -EINVAL;        *p = (unsigned int)tmp;        return count;}int lprocfs_rd_u64(char *page, char **start, off_t off,                   int count, int *eof, void *data){        LASSERT(data != NULL);        *eof = 1;        return snprintf(page, count, LPU64"\n", *(__u64 *)data);}int lprocfs_rd_atomic(char *page, char **start, off_t off,                   int count, int *eof, void *data)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?