Commit a8f62f50 authored by Stefan Hajnoczi's avatar Stefan Hajnoczi Committed by Miklos Szeredi

virtiofs: export filesystem tags through sysfs

The virtiofs filesystem is mounted using a "tag" which is exported by
the virtiofs device:

  # mount -t virtiofs <tag> /mnt

The virtiofs driver knows about all the available tags but these are
currently not exported to user space.

People have asked for these tags to be exported to user space. Most
recently Lennart Poettering has asked for it as he wants to scan the
tags and mount virtiofs automatically in certain cases.

https://gitlab.com/virtio-fs/virtiofsd/-/issues/128

This patch exports tags at /sys/fs/virtiofs/<N>/tag where N is the id of
the virtiofs device. The filesystem tag can be obtained by reading this
"tag" file.

There is also a symlink at /sys/fs/virtiofs/<N>/device that points to
the virtiofs device that exports this tag.

This patch converts the existing struct virtio_fs into a full kobject.
It already had a refcount so it's an easy change. The virtio_fs objects
can then be exposed in a kset at /sys/fs/virtiofs/. Note that virtio_fs
objects may live slightly longer than we wish for them to be exposed to
userspace, so kobject_del() is called explicitly when the underlying
virtio_device is removed. The virtio_fs object is freed when all
references are dropped (e.g. active mounts) but disappears as soon as
the virtiofs device is gone.
Originally-by: default avatarVivek Goyal <vgoyal@redhat.com>
Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: default avatarVivek Goyal <vgoyal@redhat.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 40488cc1
What: /sys/fs/virtiofs/<n>/tag
Date: Feb 2024
Contact: virtio-fs@lists.linux.dev
Description:
[RO] The mount "tag" that can be used to mount this filesystem.
What: /sys/fs/virtiofs/<n>/device
Date: Feb 2024
Contact: virtio-fs@lists.linux.dev
Description:
Symlink to the virtio device that exports this filesystem.
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
static DEFINE_MUTEX(virtio_fs_mutex); static DEFINE_MUTEX(virtio_fs_mutex);
static LIST_HEAD(virtio_fs_instances); static LIST_HEAD(virtio_fs_instances);
/* The /sys/fs/virtio_fs/ kset */
static struct kset *virtio_fs_kset;
enum { enum {
VQ_HIPRIO, VQ_HIPRIO,
VQ_REQUEST VQ_REQUEST
...@@ -55,7 +58,7 @@ struct virtio_fs_vq { ...@@ -55,7 +58,7 @@ struct virtio_fs_vq {
/* A virtio-fs device instance */ /* A virtio-fs device instance */
struct virtio_fs { struct virtio_fs {
struct kref refcount; struct kobject kobj;
struct list_head list; /* on virtio_fs_instances */ struct list_head list; /* on virtio_fs_instances */
char *tag; char *tag;
struct virtio_fs_vq *vqs; struct virtio_fs_vq *vqs;
...@@ -161,18 +164,40 @@ static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq) ...@@ -161,18 +164,40 @@ static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq)
complete(&fsvq->in_flight_zero); complete(&fsvq->in_flight_zero);
} }
static void release_virtio_fs_obj(struct kref *ref) static ssize_t tag_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct virtio_fs *fs = container_of(kobj, struct virtio_fs, kobj);
return sysfs_emit(buf, fs->tag);
}
static struct kobj_attribute virtio_fs_tag_attr = __ATTR_RO(tag);
static struct attribute *virtio_fs_attrs[] = {
&virtio_fs_tag_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(virtio_fs);
static void virtio_fs_ktype_release(struct kobject *kobj)
{ {
struct virtio_fs *vfs = container_of(ref, struct virtio_fs, refcount); struct virtio_fs *vfs = container_of(kobj, struct virtio_fs, kobj);
kfree(vfs->vqs); kfree(vfs->vqs);
kfree(vfs); kfree(vfs);
} }
static const struct kobj_type virtio_fs_ktype = {
.release = virtio_fs_ktype_release,
.sysfs_ops = &kobj_sysfs_ops,
.default_groups = virtio_fs_groups,
};
/* Make sure virtiofs_mutex is held */ /* Make sure virtiofs_mutex is held */
static void virtio_fs_put(struct virtio_fs *fs) static void virtio_fs_put(struct virtio_fs *fs)
{ {
kref_put(&fs->refcount, release_virtio_fs_obj); kobject_put(&fs->kobj);
} }
static void virtio_fs_fiq_release(struct fuse_iqueue *fiq) static void virtio_fs_fiq_release(struct fuse_iqueue *fiq)
...@@ -243,25 +268,44 @@ static void virtio_fs_start_all_queues(struct virtio_fs *fs) ...@@ -243,25 +268,44 @@ static void virtio_fs_start_all_queues(struct virtio_fs *fs)
} }
/* Add a new instance to the list or return -EEXIST if tag name exists*/ /* Add a new instance to the list or return -EEXIST if tag name exists*/
static int virtio_fs_add_instance(struct virtio_fs *fs) static int virtio_fs_add_instance(struct virtio_device *vdev,
struct virtio_fs *fs)
{ {
struct virtio_fs *fs2; struct virtio_fs *fs2;
bool duplicate = false; int ret;
mutex_lock(&virtio_fs_mutex); mutex_lock(&virtio_fs_mutex);
list_for_each_entry(fs2, &virtio_fs_instances, list) { list_for_each_entry(fs2, &virtio_fs_instances, list) {
if (strcmp(fs->tag, fs2->tag) == 0) if (strcmp(fs->tag, fs2->tag) == 0) {
duplicate = true; mutex_unlock(&virtio_fs_mutex);
return -EEXIST;
}
}
/* Use the virtio_device's index as a unique identifier, there is no
* need to allocate our own identifiers because the virtio_fs instance
* is only visible to userspace as long as the underlying virtio_device
* exists.
*/
fs->kobj.kset = virtio_fs_kset;
ret = kobject_add(&fs->kobj, NULL, "%d", vdev->index);
if (ret < 0) {
mutex_unlock(&virtio_fs_mutex);
return ret;
}
ret = sysfs_create_link(&fs->kobj, &vdev->dev.kobj, "device");
if (ret < 0) {
kobject_del(&fs->kobj);
mutex_unlock(&virtio_fs_mutex);
return ret;
} }
if (!duplicate) list_add_tail(&fs->list, &virtio_fs_instances);
list_add_tail(&fs->list, &virtio_fs_instances);
mutex_unlock(&virtio_fs_mutex); mutex_unlock(&virtio_fs_mutex);
if (duplicate)
return -EEXIST;
return 0; return 0;
} }
...@@ -274,7 +318,7 @@ static struct virtio_fs *virtio_fs_find_instance(const char *tag) ...@@ -274,7 +318,7 @@ static struct virtio_fs *virtio_fs_find_instance(const char *tag)
list_for_each_entry(fs, &virtio_fs_instances, list) { list_for_each_entry(fs, &virtio_fs_instances, list) {
if (strcmp(fs->tag, tag) == 0) { if (strcmp(fs->tag, tag) == 0) {
kref_get(&fs->refcount); kobject_get(&fs->kobj);
goto found; goto found;
} }
} }
...@@ -875,7 +919,7 @@ static int virtio_fs_probe(struct virtio_device *vdev) ...@@ -875,7 +919,7 @@ static int virtio_fs_probe(struct virtio_device *vdev)
fs = kzalloc(sizeof(*fs), GFP_KERNEL); fs = kzalloc(sizeof(*fs), GFP_KERNEL);
if (!fs) if (!fs)
return -ENOMEM; return -ENOMEM;
kref_init(&fs->refcount); kobject_init(&fs->kobj, &virtio_fs_ktype);
vdev->priv = fs; vdev->priv = fs;
ret = virtio_fs_read_tag(vdev, fs); ret = virtio_fs_read_tag(vdev, fs);
...@@ -897,7 +941,7 @@ static int virtio_fs_probe(struct virtio_device *vdev) ...@@ -897,7 +941,7 @@ static int virtio_fs_probe(struct virtio_device *vdev)
*/ */
virtio_device_ready(vdev); virtio_device_ready(vdev);
ret = virtio_fs_add_instance(fs); ret = virtio_fs_add_instance(vdev, fs);
if (ret < 0) if (ret < 0)
goto out_vqs; goto out_vqs;
...@@ -906,11 +950,10 @@ static int virtio_fs_probe(struct virtio_device *vdev) ...@@ -906,11 +950,10 @@ static int virtio_fs_probe(struct virtio_device *vdev)
out_vqs: out_vqs:
virtio_reset_device(vdev); virtio_reset_device(vdev);
virtio_fs_cleanup_vqs(vdev); virtio_fs_cleanup_vqs(vdev);
kfree(fs->vqs);
out: out:
vdev->priv = NULL; vdev->priv = NULL;
kfree(fs); kobject_put(&fs->kobj);
return ret; return ret;
} }
...@@ -934,6 +977,8 @@ static void virtio_fs_remove(struct virtio_device *vdev) ...@@ -934,6 +977,8 @@ static void virtio_fs_remove(struct virtio_device *vdev)
mutex_lock(&virtio_fs_mutex); mutex_lock(&virtio_fs_mutex);
/* This device is going away. No one should get new reference */ /* This device is going away. No one should get new reference */
list_del_init(&fs->list); list_del_init(&fs->list);
sysfs_remove_link(&fs->kobj, "device");
kobject_del(&fs->kobj);
virtio_fs_stop_all_queues(fs); virtio_fs_stop_all_queues(fs);
virtio_fs_drain_all_queues_locked(fs); virtio_fs_drain_all_queues_locked(fs);
virtio_reset_device(vdev); virtio_reset_device(vdev);
...@@ -1520,21 +1565,43 @@ static struct file_system_type virtio_fs_type = { ...@@ -1520,21 +1565,43 @@ static struct file_system_type virtio_fs_type = {
.kill_sb = virtio_kill_sb, .kill_sb = virtio_kill_sb,
}; };
static int __init virtio_fs_sysfs_init(void)
{
virtio_fs_kset = kset_create_and_add("virtiofs", NULL, fs_kobj);
if (!virtio_fs_kset)
return -ENOMEM;
return 0;
}
static void __exit virtio_fs_sysfs_exit(void)
{
kset_unregister(virtio_fs_kset);
virtio_fs_kset = NULL;
}
static int __init virtio_fs_init(void) static int __init virtio_fs_init(void)
{ {
int ret; int ret;
ret = register_virtio_driver(&virtio_fs_driver); ret = virtio_fs_sysfs_init();
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = register_virtio_driver(&virtio_fs_driver);
if (ret < 0)
goto sysfs_exit;
ret = register_filesystem(&virtio_fs_type); ret = register_filesystem(&virtio_fs_type);
if (ret < 0) { if (ret < 0)
unregister_virtio_driver(&virtio_fs_driver); goto unregister_virtio_driver;
return ret;
}
return 0; return 0;
unregister_virtio_driver:
unregister_virtio_driver(&virtio_fs_driver);
sysfs_exit:
virtio_fs_sysfs_exit();
return ret;
} }
module_init(virtio_fs_init); module_init(virtio_fs_init);
...@@ -1542,6 +1609,7 @@ static void __exit virtio_fs_exit(void) ...@@ -1542,6 +1609,7 @@ static void __exit virtio_fs_exit(void)
{ {
unregister_filesystem(&virtio_fs_type); unregister_filesystem(&virtio_fs_type);
unregister_virtio_driver(&virtio_fs_driver); unregister_virtio_driver(&virtio_fs_driver);
virtio_fs_sysfs_exit();
} }
module_exit(virtio_fs_exit); module_exit(virtio_fs_exit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment