static struct dentry *lnet_debugfs_root;
-static void kportal_memhog_free(struct libcfs_device_userstate *ldu)
-{
- struct page **level0p = &ldu->ldu_memhog_root_page;
- struct page **level1p;
- struct page **level2p;
- int count1;
- int count2;
-
- if (*level0p != NULL) {
-
- level1p = (struct page **)page_address(*level0p);
- count1 = 0;
-
- while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
- *level1p != NULL) {
-
- level2p = (struct page **)page_address(*level1p);
- count2 = 0;
-
- while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
- *level2p != NULL) {
-
- __free_page(*level2p);
- ldu->ldu_memhog_pages--;
- level2p++;
- count2++;
- }
-
- __free_page(*level1p);
- ldu->ldu_memhog_pages--;
- level1p++;
- count1++;
- }
-
- __free_page(*level0p);
- ldu->ldu_memhog_pages--;
-
- *level0p = NULL;
- }
-
- LASSERT(ldu->ldu_memhog_pages == 0);
-}
-
-static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
- gfp_t flags)
-{
- struct page **level0p;
- struct page **level1p;
- struct page **level2p;
- int count1;
- int count2;
-
- LASSERT(ldu->ldu_memhog_pages == 0);
- LASSERT(ldu->ldu_memhog_root_page == NULL);
-
- if (npages < 0)
- return -EINVAL;
-
- if (npages == 0)
- return 0;
-
- level0p = &ldu->ldu_memhog_root_page;
- *level0p = alloc_page(flags);
- if (*level0p == NULL)
- return -ENOMEM;
- ldu->ldu_memhog_pages++;
-
- level1p = (struct page **)page_address(*level0p);
- count1 = 0;
- memset(level1p, 0, PAGE_CACHE_SIZE);
-
- while (ldu->ldu_memhog_pages < npages &&
- count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
-
- if (cfs_signal_pending())
- return -EINTR;
-
- *level1p = alloc_page(flags);
- if (*level1p == NULL)
- return -ENOMEM;
- ldu->ldu_memhog_pages++;
-
- level2p = (struct page **)page_address(*level1p);
- count2 = 0;
- memset(level2p, 0, PAGE_CACHE_SIZE);
-
- while (ldu->ldu_memhog_pages < npages &&
- count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
-
- if (cfs_signal_pending())
- return -EINTR;
-
- *level2p = alloc_page(flags);
- if (*level2p == NULL)
- return -ENOMEM;
- ldu->ldu_memhog_pages++;
-
- level2p++;
- count2++;
- }
-
- level1p++;
- count1++;
- }
-
- return 0;
-}
-
/* called when opening /dev/device */
static int libcfs_psdev_open(unsigned long flags, void *args)
{
- struct libcfs_device_userstate *ldu;
-
try_module_get(THIS_MODULE);
-
- LIBCFS_ALLOC(ldu, sizeof(*ldu));
- if (ldu != NULL) {
- ldu->ldu_memhog_pages = 0;
- ldu->ldu_memhog_root_page = NULL;
- }
- *(struct libcfs_device_userstate **)args = ldu;
-
return 0;
}
/* called when closing /dev/device */
static int libcfs_psdev_release(unsigned long flags, void *args)
{
- struct libcfs_device_userstate *ldu;
-
- ldu = (struct libcfs_device_userstate *)args;
- if (ldu != NULL) {
- kportal_memhog_free(ldu);
- LIBCFS_FREE(ldu, sizeof(*ldu));
- }
-
module_put(THIS_MODULE);
return 0;
}
EXPORT_SYMBOL(libcfs_deregister_ioctl);
static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd,
- void *arg, struct libcfs_ioctl_data *data)
+ void __user *arg, struct libcfs_ioctl_data *data)
{
int err = -EINVAL;
return -EINVAL;
libcfs_debug_mark_buffer(data->ioc_inlbuf1);
return 0;
- case IOC_LIBCFS_MEMHOG:
- if (pfile->private_data == NULL) {
- err = -EINVAL;
- } else {
- kportal_memhog_free(pfile->private_data);
- /* XXX The ioc_flags is not GFP flags now, need to be fixed */
- err = kportal_memhog_alloc(pfile->private_data,
- data->ioc_count,
- data->ioc_flags);
- if (err != 0)
- kportal_memhog_free(pfile->private_data);
- }
- break;
default: {
struct libcfs_ioctl_handler *hand;
return err;
}
-static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
+static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd,
+ void __user *arg)
{
char *buf;
struct libcfs_ioctl_data *data;
return error;
}
-static const struct file_operations lnet_debugfs_file_operations = {
+static const struct file_operations lnet_debugfs_file_operations_rw = {
.open = simple_open,
.read = lnet_debugfs_read,
.write = lnet_debugfs_write,
.llseek = default_llseek,
};
+static const struct file_operations lnet_debugfs_file_operations_ro = {
+ .open = simple_open,
+ .read = lnet_debugfs_read,
+ .llseek = default_llseek,
+};
+
+static const struct file_operations lnet_debugfs_file_operations_wo = {
+ .open = simple_open,
+ .write = lnet_debugfs_write,
+ .llseek = default_llseek,
+};
+
+static const struct file_operations *lnet_debugfs_fops_select(umode_t mode)
+{
+ if (!(mode & S_IWUGO))
+ return &lnet_debugfs_file_operations_ro;
+
+ if (!(mode & S_IRUGO))
+ return &lnet_debugfs_file_operations_wo;
+
+ return &lnet_debugfs_file_operations_rw;
+}
+
void lustre_insert_debugfs(struct ctl_table *table,
const struct lnet_debugfs_symlink_def *symlinks)
{
- struct dentry *entry;
-
if (lnet_debugfs_root == NULL)
lnet_debugfs_root = debugfs_create_dir("lnet", NULL);
if (IS_ERR_OR_NULL(lnet_debugfs_root))
return;
+ /* We don't save the dentry returned in next two calls, because
+ * we don't call debugfs_remove() but rather remove_recursive()
+ */
for (; table->procname; table++)
- entry = debugfs_create_file(table->procname, table->mode,
- lnet_debugfs_root, table,
- &lnet_debugfs_file_operations);
+ debugfs_create_file(table->procname, table->mode,
+ lnet_debugfs_root, table,
+ lnet_debugfs_fops_select(table->mode));
for (; symlinks && symlinks->name; symlinks++)
- entry = debugfs_create_symlink(symlinks->name,
- lnet_debugfs_root,
- symlinks->target);
+ debugfs_create_symlink(symlinks->name, lnet_debugfs_root,
+ symlinks->target);
}
EXPORT_SYMBOL_GPL(lustre_insert_debugfs);