Commit 935c6912b198f60a812b7dada21027b5aac7c461
Committed by
Al Viro
1 parent
66f592e2ec
Exists in
smarc_imx_lf-5.15.y
and in
13 other branches
ipc: Convert mqueue fs to fs_context
Convert the mqueue filesystem to use the filesystem context stuff.
Notes:
(1) The relevant ipc namespace is selected in when the context is
initialised (and it defaults to the current task's ipc namespace).
The caller can override this before calling vfs_get_tree().
(2) Rather than simply calling kern_mount_data(), mq_init_ns() and
mq_internal_mount() create a context, adjust it and then do the rest
of the mount procedure.
(3) The lazy mqueue mounting on creation of a new namespace is retained
from a previous patch, but the avoidance of sget() if no superblock
yet exists is reverted and the superblock is again keyed on the
namespace pointer.
Yes, there was a performance gain in not searching the superblock
hash, but it's only paid once per ipc namespace - and only if someone
uses mqueue within that namespace, so I'm not sure it's worth it,
especially as calling sget() allows avoidance of recursion.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 2 changed files with 73 additions and 23 deletions Side-by-side Diff
ipc/mqueue.c
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | #include <linux/pagemap.h> |
| 19 | 19 | #include <linux/file.h> |
| 20 | 20 | #include <linux/mount.h> |
| 21 | +#include <linux/fs_context.h> | |
| 21 | 22 | #include <linux/namei.h> |
| 22 | 23 | #include <linux/sysctl.h> |
| 23 | 24 | #include <linux/poll.h> |
| ... | ... | @@ -42,6 +43,10 @@ |
| 42 | 43 | #include <net/sock.h> |
| 43 | 44 | #include "util.h" |
| 44 | 45 | |
| 46 | +struct mqueue_fs_context { | |
| 47 | + struct ipc_namespace *ipc_ns; | |
| 48 | +}; | |
| 49 | + | |
| 45 | 50 | #define MQUEUE_MAGIC 0x19800202 |
| 46 | 51 | #define DIRENT_SIZE 20 |
| 47 | 52 | #define FILENT_SIZE 80 |
| 48 | 53 | |
| ... | ... | @@ -87,9 +92,11 @@ |
| 87 | 92 | unsigned long qsize; /* size of queue in memory (sum of all msgs) */ |
| 88 | 93 | }; |
| 89 | 94 | |
| 95 | +static struct file_system_type mqueue_fs_type; | |
| 90 | 96 | static const struct inode_operations mqueue_dir_inode_operations; |
| 91 | 97 | static const struct file_operations mqueue_file_operations; |
| 92 | 98 | static const struct super_operations mqueue_super_ops; |
| 99 | +static const struct fs_context_operations mqueue_fs_context_ops; | |
| 93 | 100 | static void remove_notification(struct mqueue_inode_info *info); |
| 94 | 101 | |
| 95 | 102 | static struct kmem_cache *mqueue_inode_cachep; |
| ... | ... | @@ -322,7 +329,7 @@ |
| 322 | 329 | return ERR_PTR(ret); |
| 323 | 330 | } |
| 324 | 331 | |
| 325 | -static int mqueue_fill_super(struct super_block *sb, void *data, int silent) | |
| 332 | +static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc) | |
| 326 | 333 | { |
| 327 | 334 | struct inode *inode; |
| 328 | 335 | struct ipc_namespace *ns = sb->s_fs_info; |
| 329 | 336 | |
| 330 | 337 | |
| ... | ... | @@ -343,20 +350,58 @@ |
| 343 | 350 | return 0; |
| 344 | 351 | } |
| 345 | 352 | |
| 346 | -static struct dentry *mqueue_mount(struct file_system_type *fs_type, | |
| 347 | - int flags, const char *dev_name, | |
| 348 | - void *data) | |
| 353 | +static int mqueue_get_tree(struct fs_context *fc) | |
| 349 | 354 | { |
| 350 | - struct ipc_namespace *ns; | |
| 351 | - if (flags & SB_KERNMOUNT) { | |
| 352 | - ns = data; | |
| 353 | - data = NULL; | |
| 354 | - } else { | |
| 355 | - ns = current->nsproxy->ipc_ns; | |
| 356 | - } | |
| 357 | - return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super); | |
| 355 | + struct mqueue_fs_context *ctx = fc->fs_private; | |
| 356 | + | |
| 357 | + put_user_ns(fc->user_ns); | |
| 358 | + fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns); | |
| 359 | + fc->s_fs_info = ctx->ipc_ns; | |
| 360 | + return vfs_get_super(fc, vfs_get_keyed_super, mqueue_fill_super); | |
| 358 | 361 | } |
| 359 | 362 | |
| 363 | +static void mqueue_fs_context_free(struct fs_context *fc) | |
| 364 | +{ | |
| 365 | + struct mqueue_fs_context *ctx = fc->fs_private; | |
| 366 | + | |
| 367 | + if (ctx->ipc_ns) | |
| 368 | + put_ipc_ns(ctx->ipc_ns); | |
| 369 | + kfree(ctx); | |
| 370 | +} | |
| 371 | + | |
| 372 | +static int mqueue_init_fs_context(struct fs_context *fc) | |
| 373 | +{ | |
| 374 | + struct mqueue_fs_context *ctx; | |
| 375 | + | |
| 376 | + ctx = kzalloc(sizeof(struct mqueue_fs_context), GFP_KERNEL); | |
| 377 | + if (!ctx) | |
| 378 | + return -ENOMEM; | |
| 379 | + | |
| 380 | + ctx->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); | |
| 381 | + fc->fs_private = ctx; | |
| 382 | + fc->ops = &mqueue_fs_context_ops; | |
| 383 | + return 0; | |
| 384 | +} | |
| 385 | + | |
| 386 | +static struct vfsmount *mq_create_mount(struct ipc_namespace *ns) | |
| 387 | +{ | |
| 388 | + struct mqueue_fs_context *ctx; | |
| 389 | + struct fs_context *fc; | |
| 390 | + struct vfsmount *mnt; | |
| 391 | + | |
| 392 | + fc = fs_context_for_mount(&mqueue_fs_type, SB_KERNMOUNT); | |
| 393 | + if (IS_ERR(fc)) | |
| 394 | + return ERR_CAST(fc); | |
| 395 | + | |
| 396 | + ctx = fc->fs_private; | |
| 397 | + put_ipc_ns(ctx->ipc_ns); | |
| 398 | + ctx->ipc_ns = get_ipc_ns(ns); | |
| 399 | + | |
| 400 | + mnt = fc_mount(fc); | |
| 401 | + put_fs_context(fc); | |
| 402 | + return mnt; | |
| 403 | +} | |
| 404 | + | |
| 360 | 405 | static void init_once(void *foo) |
| 361 | 406 | { |
| 362 | 407 | struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo; |
| 363 | 408 | |
| 364 | 409 | |
| ... | ... | @@ -1522,15 +1567,22 @@ |
| 1522 | 1567 | .statfs = simple_statfs, |
| 1523 | 1568 | }; |
| 1524 | 1569 | |
| 1570 | +static const struct fs_context_operations mqueue_fs_context_ops = { | |
| 1571 | + .free = mqueue_fs_context_free, | |
| 1572 | + .get_tree = mqueue_get_tree, | |
| 1573 | +}; | |
| 1574 | + | |
| 1525 | 1575 | static struct file_system_type mqueue_fs_type = { |
| 1526 | - .name = "mqueue", | |
| 1527 | - .mount = mqueue_mount, | |
| 1528 | - .kill_sb = kill_litter_super, | |
| 1529 | - .fs_flags = FS_USERNS_MOUNT, | |
| 1576 | + .name = "mqueue", | |
| 1577 | + .init_fs_context = mqueue_init_fs_context, | |
| 1578 | + .kill_sb = kill_litter_super, | |
| 1579 | + .fs_flags = FS_USERNS_MOUNT, | |
| 1530 | 1580 | }; |
| 1531 | 1581 | |
| 1532 | 1582 | int mq_init_ns(struct ipc_namespace *ns) |
| 1533 | 1583 | { |
| 1584 | + struct vfsmount *m; | |
| 1585 | + | |
| 1534 | 1586 | ns->mq_queues_count = 0; |
| 1535 | 1587 | ns->mq_queues_max = DFLT_QUEUESMAX; |
| 1536 | 1588 | ns->mq_msg_max = DFLT_MSGMAX; |
| ... | ... | @@ -1538,12 +1590,10 @@ |
| 1538 | 1590 | ns->mq_msg_default = DFLT_MSG; |
| 1539 | 1591 | ns->mq_msgsize_default = DFLT_MSGSIZE; |
| 1540 | 1592 | |
| 1541 | - ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns); | |
| 1542 | - if (IS_ERR(ns->mq_mnt)) { | |
| 1543 | - int err = PTR_ERR(ns->mq_mnt); | |
| 1544 | - ns->mq_mnt = NULL; | |
| 1545 | - return err; | |
| 1546 | - } | |
| 1593 | + m = mq_create_mount(ns); | |
| 1594 | + if (IS_ERR(m)) | |
| 1595 | + return PTR_ERR(m); | |
| 1596 | + ns->mq_mnt = m; | |
| 1547 | 1597 | return 0; |
| 1548 | 1598 | } |
| 1549 | 1599 |