diff --git a/buffers/zio-buf-kmalloc.c b/buffers/zio-buf-kmalloc.c index 0155e2923c92aa83ab705e1272ab8c352d7bbd9b..450ead8136cf8f32a8544467250af55508a2d735 100644 --- a/buffers/zio-buf-kmalloc.c +++ b/buffers/zio-buf-kmalloc.c @@ -243,19 +243,6 @@ static const struct zio_buffer_operations zbk_buffer_ops = { .destroy = zbk_destroy, }; -/* - * File operations. We only have read and write: mmap is definitely - * not suitable here, and open/release are not needed. - */ - -static const struct file_operations zbk_file_ops = { - .owner = THIS_MODULE, - .read = zio_generic_read, - .write = zio_generic_write, - .poll = zio_generic_poll, - .release = zio_generic_release, -}; - static struct zio_buffer_type zbk_buffer = { .owner = THIS_MODULE, .zattr_set = { @@ -263,7 +250,7 @@ static struct zio_buffer_type zbk_buffer = { }, .s_op = &zbk_sysfs_ops, .b_op = &zbk_buffer_ops, - .f_op = &zbk_file_ops, + .f_op = &zio_generic_file_operations, }; static int __init zbk_init(void) diff --git a/include/linux/zio-buffer.h b/include/linux/zio-buffer.h index df987d13f0d16c5b205add7a80a5d5819c620a30..7cda57b78a106cf45e232e628bea48af957e862d 100644 --- a/include/linux/zio-buffer.h +++ b/include/linux/zio-buffer.h @@ -26,26 +26,27 @@ struct zio_buffer_type { struct module *owner; struct list_head list; /* instances, and list lock */ struct spinlock lock; - unsigned long flags; /* to be defined */ + unsigned long flags; - /* file operations (read/write etc) are buffer-specific too */ const struct zio_sysfs_operations *s_op; const struct zio_buffer_operations *b_op; + /* + * file operations (read/write etc) are buffer-specific too, but + * you are strongly suggested to use zio_generic_file_operations. + * If the field is NULL, you'll get ENODEV when opening the cdev. + */ const struct file_operations *f_op; + const struct vm_operations *v_op; /* default attributes for instance */ struct zio_attribute_set zattr_set; }; #define to_zio_buf(ptr) container_of(ptr, struct zio_buffer_type, head.kobj) -/* read and write may often be the generic ones */ -ssize_t zio_generic_read(struct file *, char __user *, - size_t, loff_t *); -ssize_t zio_generic_write(struct file *, const char __user *, - size_t, loff_t *); -unsigned int zio_generic_poll(struct file *, struct poll_table_struct *); -int zio_generic_release(struct inode *inode, struct file *f); +/* buffer_type->flags */ +#define ZIO_BFLAG_ALLOC_FOPS 0x00000001 /* set by zio-core */ +extern const struct file_operations zio_generic_file_operations; int __must_check zio_register_buf(struct zio_buffer_type *zbuf, const char *name); @@ -141,10 +142,4 @@ struct zio_f_priv { enum zio_cdev_type type; }; -ssize_t zio_generic_read(struct file *f, char __user *ubuf, - size_t count, loff_t *offp); -ssize_t zio_generic_write(struct file *f, const char __user *ubuf, - size_t count, loff_t *offp); -unsigned int zio_generic_poll(struct file *f, struct poll_table_struct *w); - #endif /* __ZIO_BUFFER_H__ */ diff --git a/include/linux/zio.h b/include/linux/zio.h index 588548fad71e4dde3053a226c6c04ee1e01f8ae3..eaf1627fc3acfd890e4f8c2becc3a5968f722863 100644 --- a/include/linux/zio.h +++ b/include/linux/zio.h @@ -266,6 +266,9 @@ void zio_default_buffer_exit(void); int zio_default_trigger_init(void); void zio_default_trigger_exit(void); +int zio_init_buffer_fops(struct zio_buffer_type *zbuf); +int zio_fini_buffer_fops(struct zio_buffer_type *zbuf); + #endif /* __ZIO_INTERNAL__ */ #endif /* __KERNEL__ */ diff --git a/zio-cdev.c b/zio-cdev.c index 54488beda8ef3638fedbebb835e702272101d89a..9bfbd3235ca043d3a7a63770ccf0efb5f1f324c4 100644 --- a/zio-cdev.c +++ b/zio-cdev.c @@ -125,9 +125,15 @@ static int zio_f_open(struct inode *ino, struct file *f) chan = __zio_minor_to_chan(ino->i_rdev); if (!chan) { pr_err("ZIO: can't retrieve channel for minor %i\n", minor); + zio_device_put(ino->i_rdev); return -EBUSY; } zbuf = chan->cset->zbuf; + if (!zbuf->f_op) { + zio_device_put(ino->i_rdev); + return -ENODEV; + } + f->private_data = NULL; priv = kzalloc(sizeof(struct zio_f_priv), GFP_KERNEL); if (!priv) @@ -370,7 +376,7 @@ static int __zio_write_allowed(struct zio_f_priv *priv) * work for most buffer types, and are exported for use in their * buffer operations. */ -ssize_t zio_generic_read(struct file *f, char __user *ubuf, +static ssize_t zio_generic_read(struct file *f, char __user *ubuf, size_t count, loff_t *offp) { struct zio_f_priv *priv = f->private_data; @@ -418,9 +424,8 @@ ssize_t zio_generic_read(struct file *f, char __user *ubuf, } return count; } -EXPORT_SYMBOL(zio_generic_read); -ssize_t zio_generic_write(struct file *f, const char __user *ubuf, +static ssize_t zio_generic_write(struct file *f, const char __user *ubuf, size_t count, loff_t *offp) { struct zio_f_priv *priv = f->private_data; @@ -475,9 +480,9 @@ ssize_t zio_generic_write(struct file *f, const char __user *ubuf, *offp += count; return count; } -EXPORT_SYMBOL(zio_generic_write); -unsigned int zio_generic_poll(struct file *f, struct poll_table_struct *w) +static unsigned int zio_generic_poll(struct file *f, + struct poll_table_struct *w) { struct zio_f_priv *priv = f->private_data; struct zio_bi *bi = priv->chan->bi; @@ -485,9 +490,8 @@ unsigned int zio_generic_poll(struct file *f, struct poll_table_struct *w) poll_wait(f, &bi->q, w); return __zio_read_allowed(priv) | __zio_write_allowed(priv); } -EXPORT_SYMBOL(zio_generic_poll); -int zio_generic_release(struct inode *inode, struct file *f) +static int zio_generic_release(struct inode *inode, struct file *f) { struct zio_f_priv *priv = f->private_data; @@ -496,5 +500,45 @@ int zio_generic_release(struct inode *inode, struct file *f) zio_device_put(inode->i_rdev); return 0; } -EXPORT_SYMBOL(zio_generic_release); +const struct file_operations zio_generic_file_operations = { + /* no owner: this template is copied over */ + .read = zio_generic_read, + .write = zio_generic_write, + .poll = zio_generic_poll, + .release = zio_generic_release, +}; +/* Export, so buffers can use it or internal function */ +EXPORT_SYMBOL(zio_generic_file_operations); + +/* Currently, this is a "all or nothing" choice */ +int zio_init_buffer_fops(struct zio_buffer_type *zbuf) +{ + struct file_operations *ops; + + /* Current fops may be NULL (buffer for in-kernel data handling */ + if (!zbuf->f_op) + return 0; + if (zbuf->f_op != &zio_generic_file_operations) + return 0; + + /* If it's the generic ones, we must clone to fit the owner field */ + ops = kzalloc(sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + zbuf->flags |= ZIO_BFLAG_ALLOC_FOPS; + *ops = zio_generic_file_operations; + ops->owner = zbuf->owner; + zbuf->f_op = ops; + return 0; +} + +int zio_fini_buffer_fops(struct zio_buffer_type *zbuf) +{ + if (!(zbuf->flags & ZIO_BFLAG_ALLOC_FOPS)) + return 0; + zbuf->flags &= ~ZIO_BFLAG_ALLOC_FOPS; + kfree(zbuf->f_op); + zbuf->f_op = &zio_generic_file_operations; + return 0; +} diff --git a/zio-sys.c b/zio-sys.c index 5cd661c9f87fdc157f5b990eb61c76519ed72495..107da391d346d31573b002dfec35cd67986c4b9b 100644 --- a/zio-sys.c +++ b/zio-sys.c @@ -1671,10 +1671,16 @@ int zio_register_buf(struct zio_buffer_type *zbuf, const char *name) if (!zbuf || !name) return -EINVAL; + err = zio_init_buffer_fops(zbuf); + if (err < 0) + return err; + err = zobj_register(&zstat->all_buffer_types, &zbuf->head, ZBUF, zbuf->owner, name); - if (err) + if (err) { + zio_fini_buffer_fops(zbuf); return err; + } zbuf->zattr_set.n_std_attr = ZATTR_STD_NUM_ZBUF; INIT_LIST_HEAD(&zbuf->list); spin_lock_init(&zbuf->lock); @@ -1687,6 +1693,7 @@ void zio_unregister_buf(struct zio_buffer_type *zbuf) { if (!zbuf) return; + zio_fini_buffer_fops(zbuf); zobj_unregister(&zstat->all_buffer_types, &zbuf->head); } EXPORT_SYMBOL(zio_unregister_buf);