From: Pavel Emelyanov <xemul-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
To: Serge Hallyn <serue-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>,
Oren Laadan <orenl-eQaUEPhvms7ENvBUuze7eA@public.gmane.org>
Cc: Linux Containers
<containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org>,
Paul Menage <menage-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Subject: [PATCH 2/4] The character devices layer changes
Date: Tue, 08 Jan 2008 12:12:51 +0300 [thread overview]
Message-ID: <47833E93.6010108@openvz.org> (raw)
In-Reply-To: <47833C3A.8090106-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
These changes include the API for the control group
to map/remap/unmap the devices with their permissions
and one important thing.
The fact is that the struct cdev is cached in the inode
for faster access, so once we looked one up we go through
the fast path and omit the kobj_lookup() call. This is no
longer good when we restrict the access to cdevs.
To address this issue, I store the last_perm and last(_map)
fields on the struct cdev (and protect them with the cdev_lock)
and force the re-lookup in the kobj mappings if needed.
I know, this might be slow, but I have two points for it:
1. The re-lookup happens on open() only which is not
a fast-path. Besides, this is so for block layer and
nobody complains;
2. On a well-isolated setup, when each container has its
own filesystem this is no longer a problem - each
cgroup will cache the cdev on its inode and work good.
Signed-off-by: Pavel Emelyanov <xemul-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
---
diff --git a/fs/char_dev.c b/fs/char_dev.c
index c3bfa76..2b821ef 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -22,6 +22,8 @@
#include <linux/mutex.h>
#include <linux/backing-dev.h>
+#include <linux/devscontrol.h>
+
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
@@ -362,17 +364,25 @@ int chrdev_open(struct inode * inode, struct file * filp)
struct cdev *p;
struct cdev *new = NULL;
int ret = 0;
+ struct kobj_map *map;
+ mode_t mode;
+
+ map = task_cdev_map(current);
+ if (map == NULL)
+ map = cdev_map;
spin_lock(&cdev_lock);
p = inode->i_cdev;
- if (!p) {
+ if (!p || p->last != map) {
struct kobject *kobj;
int idx;
+
spin_unlock(&cdev_lock);
- kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
+ kobj = kobj_lookup(map, inode->i_rdev, &mode, &idx);
if (!kobj)
return -ENXIO;
new = container_of(kobj, struct cdev, kobj);
+ BUG_ON(p != NULL && p != new);
spin_lock(&cdev_lock);
p = inode->i_cdev;
if (!p) {
@@ -382,12 +392,24 @@ int chrdev_open(struct inode * inode, struct file * filp)
new = NULL;
} else if (!cdev_get(p))
ret = -ENXIO;
+ else {
+ p->last = map;
+ p->last_mode = mode;
+ }
} else if (!cdev_get(p))
ret = -ENXIO;
+ else
+ mode = p->last_mode;
spin_unlock(&cdev_lock);
cdev_put(new);
if (ret)
return ret;
+
+ if ((filp->f_mode & mode) != filp->f_mode) {
+ cdev_put(p);
+ return -EACCES;
+ }
+
filp->f_op = fops_get(p->ops);
if (!filp->f_op) {
cdev_put(p);
@@ -461,6 +483,64 @@ int cdev_add(struct cdev *p, dev_t dev, unsigned count)
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
+#ifdef CONFIG_CGROUP_DEVS
+static inline void cdev_map_reset(struct kobj_map *map, struct cdev *c)
+{
+ spin_lock(&cdev_lock);
+ if (c->last == map)
+ c->last = NULL;
+ spin_unlock(&cdev_lock);
+}
+
+int cdev_add_to_map(struct kobj_map *map, dev_t dev, int all, mode_t mode)
+{
+ int tmp;
+ struct kobject *k;
+ struct cdev *c;
+
+ k = kobj_lookup(cdev_map, dev, NULL, &tmp);
+ if (k == NULL)
+ return -ENODEV;
+
+ c = container_of(k, struct cdev, kobj);
+ tmp = kobj_remap(map, dev, mode, all ? MINORMASK : 1, NULL,
+ exact_match, exact_lock, c);
+ if (tmp < 0) {
+ cdev_put(c);
+ return tmp;
+ }
+
+ cdev_map_reset(map, c);
+ return 0;
+}
+
+int cdev_del_from_map(struct kobj_map *map, dev_t dev, int all)
+{
+ int tmp;
+ struct kobject *k;
+ struct cdev *c;
+
+ k = kobj_lookup(cdev_map, dev, NULL, &tmp);
+ if (k == NULL)
+ return -ENODEV;
+
+ c = container_of(k, struct cdev, kobj);
+ kobj_unmap(map, dev, all ? MINORMASK : 1);
+
+ cdev_map_reset(map, c);
+
+ cdev_put(c);
+ cdev_put(c);
+ return 0;
+}
+
+void cdev_iterate_map(struct kobj_map *map,
+ int (*fn)(dev_t, int, mode_t, void *), void *x)
+{
+ kobj_map_iterate(map, fn, x);
+}
+#endif
+
static void cdev_unmap(dev_t dev, unsigned count)
{
kobj_unmap(cdev_map, dev, count);
@@ -542,9 +622,19 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
return NULL;
}
+struct kobj_map *cdev_map_init(void)
+{
+ return kobj_map_init(base_probe, &chrdevs_lock);
+}
+
+void cdev_map_fini(struct kobj_map *map)
+{
+ kobj_map_fini(map);
+}
+
void __init chrdev_init(void)
{
- cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
+ cdev_map = cdev_map_init();
bdi_init(&directly_mappable_cdev_bdi);
}
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index 1e29b13..d72a2a1 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -9,6 +9,7 @@
struct file_operations;
struct inode;
struct module;
+struct kobj_map;
struct cdev {
struct kobject kobj;
@@ -17,6 +18,8 @@ struct cdev {
struct list_head list;
dev_t dev;
unsigned int count;
+ struct kobj_map *last;
+ mode_t last_mode;
};
void cdev_init(struct cdev *, const struct file_operations *);
@@ -33,5 +36,11 @@ void cd_forget(struct inode *);
extern struct backing_dev_info directly_mappable_cdev_bdi;
+int cdev_add_to_map(struct kobj_map *map, dev_t dev, int all, mode_t mode);
+int cdev_del_from_map(struct kobj_map *map, dev_t dev, int all);
+struct kobj_map *cdev_map_init(void);
+void cdev_map_fini(struct kobj_map *map);
+void cdev_iterate_map(struct kobj_map *,
+ int (*fn)(dev_t, int, mode_t, void *), void *);
#endif
#endif
next prev parent reply other threads:[~2008-01-08 9:12 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-08 9:02 [PATCH 0/4] Devices accessibility control group (v2) Pavel Emelyanov
[not found] ` <47833C3A.8090106-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-08 9:07 ` [PATCH 1/4] Some changes in the kobject mapper Pavel Emelyanov
[not found] ` <47833D43.3090703-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-08 18:36 ` Daniel Hokka Zakrisson
[not found] ` <4783C2B4.7000501-nym3zxDgnZcAvxtiuMwx3w@public.gmane.org>
2008-01-08 19:17 ` Dave Hansen
2008-01-08 9:12 ` Pavel Emelyanov [this message]
[not found] ` <47833E93.6010108-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-14 17:03 ` [PATCH 2/4] The character devices layer changes Serge E. Hallyn
[not found] ` <20080114170333.GA15077-6s5zFf/epYLPQpwDFJZrxKsjOiXwFzmk@public.gmane.org>
2008-01-15 8:05 ` Pavel Emelyanov
[not found] ` <478C6942.4050903-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-15 14:54 ` Serge E. Hallyn
2008-01-08 9:15 ` [PATCH 3/4] The block " Pavel Emelyanov
2008-01-08 9:18 ` [PATCH 4/4] The control group itself Pavel Emelyanov
[not found] ` <47833FF6.6060901-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-14 17:40 ` Serge E. Hallyn
[not found] ` <20080114174056.GB15077-6s5zFf/epYLPQpwDFJZrxKsjOiXwFzmk@public.gmane.org>
2008-01-15 7:53 ` Pavel Emelyanov
[not found] ` <478C6669.7070705-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-15 14:44 ` Serge E. Hallyn
[not found] ` <20080115144440.GE4453-6s5zFf/epYLPQpwDFJZrxKsjOiXwFzmk@public.gmane.org>
2008-01-15 16:13 ` Paul Menage
[not found] ` <6599ad830801150813s6a5a7374qd25b6d6206d5896a-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-01-15 17:49 ` Serge E. Hallyn
[not found] ` <20080115174941.GA11638-6s5zFf/epYLPQpwDFJZrxKsjOiXwFzmk@public.gmane.org>
2008-01-15 17:54 ` Paul Menage
[not found] ` <6599ad830801150954w7e1b6db0p4dd737730f407348-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-01-15 18:17 ` Serge E. Hallyn
2008-01-14 21:54 ` Paul Menage
[not found] ` <6599ad830801141354p5b165cdao8d6184adb9ab61b6-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-01-15 7:58 ` Pavel Emelyanov
2008-01-12 21:20 ` [PATCH 0/4] Devices accessibility control group (v2) sukadev-r/Jw6+rmf7HQT0dZR+AlfA
[not found] ` <20080112212014.GA12085-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-01-14 7:52 ` Pavel Emelyanov
[not found] ` <478B14DB.4000106-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-14 17:42 ` sukadev-r/Jw6+rmf7HQT0dZR+AlfA
[not found] ` <20080114174220.GA17825-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-01-15 8:22 ` Pavel Emelyanov
[not found] ` <478C6D2B.6020904-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-01-17 6:26 ` sukadev-r/Jw6+rmf7HQT0dZR+AlfA
[not found] ` <20080117062605.GA24475-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-01-21 8:31 ` Pavel Emelyanov
2008-01-14 21:18 ` Paul Menage
[not found] ` <6599ad830801141318h121a6a80h9af68c52431c48b8-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-01-15 8:06 ` Pavel Emelyanov
-- strict thread matches above, loose matches on Subject: below --
2008-02-07 12:56 [PATCH 0/4] Devices accessibility control group (v3, release candidate) Pavel Emelyanov
[not found] ` <47AAFFF2.9030804-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
2008-02-07 12:59 ` [PATCH 2/4] The character devices layer changes Pavel Emelyanov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47833E93.6010108@openvz.org \
--to=xemul-gefaqzzx7r8dnm+yrofe0a@public.gmane.org \
--cc=containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org \
--cc=menage-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org \
--cc=orenl-eQaUEPhvms7ENvBUuze7eA@public.gmane.org \
--cc=serue-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.