+
+/* 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 >= CFS_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, CFS_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 = 0;
+
+ 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);
+
+ 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);
+