fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / md / dm-ioctl.c
index d13bb15..7b76b41 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/dm-ioctl.h>
 #include <linux/hdreg.h>
+#include <linux/vs_context.h>
 
 #include <asm/uaccess.h>
 
@@ -100,7 +101,8 @@ static struct hash_cell *__get_name_cell(const char *str)
        unsigned int h = hash_str(str);
 
        list_for_each_entry (hc, _name_buckets + h, name_list)
-               if (!strcmp(hc->name, str)) {
+               if (vx_check(dm_get_xid(hc->md), VS_WATCH_P|VS_IDENT) &&
+                       !strcmp(hc->name, str)) {
                        dm_get(hc->md);
                        return hc;
                }
@@ -114,7 +116,8 @@ static struct hash_cell *__get_uuid_cell(const char *str)
        unsigned int h = hash_str(str);
 
        list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
-               if (!strcmp(hc->uuid, str)) {
+               if (vx_check(dm_get_xid(hc->md), VS_WATCH_P|VS_IDENT) &&
+                       !strcmp(hc->uuid, str)) {
                        dm_get(hc->md);
                        return hc;
                }
@@ -349,6 +352,9 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
 
 static int remove_all(struct dm_ioctl *param, size_t param_size)
 {
+       if (!vx_check(0, VS_ADMIN))
+               return -EPERM;
+
        dm_hash_remove_all(1);
        param->data_size = 0;
        return 0;
@@ -396,6 +402,8 @@ static int list_devices(struct dm_ioctl *param, size_t param_size)
         */
        for (i = 0; i < NUM_BUCKETS; i++) {
                list_for_each_entry (hc, _name_buckets + i, name_list) {
+                       if (!vx_check(dm_get_xid(hc->md), VS_WATCH_P|VS_IDENT))
+                               continue;
                        needed += sizeof(struct dm_name_list);
                        needed += strlen(hc->name) + 1;
                        needed += ALIGN_MASK;
@@ -419,6 +427,8 @@ static int list_devices(struct dm_ioctl *param, size_t param_size)
         */
        for (i = 0; i < NUM_BUCKETS; i++) {
                list_for_each_entry (hc, _name_buckets + i, name_list) {
+                       if (!vx_check(dm_get_xid(hc->md), VS_WATCH_P|VS_IDENT))
+                               continue;
                        if (old_nl)
                                old_nl->next = (uint32_t) ((void *) nl -
                                                           (void *) old_nl);
@@ -606,9 +616,15 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
                return __get_name_cell(param->name);
 
        md = dm_get_md(huge_decode_dev(param->dev));
-       if (md)
+       if (!md)
+               goto out;
+
+       if (vx_check(dm_get_xid(md), VS_WATCH_P|VS_IDENT))
                mdptr = dm_get_mdptr(md);
 
+       if (!mdptr)
+               dm_put(md);
+out:
        return mdptr;
 }
 
@@ -760,7 +776,7 @@ out:
 static int do_suspend(struct dm_ioctl *param)
 {
        int r = 0;
-       int do_lockfs = 1;
+       unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
        struct mapped_device *md;
 
        md = find_device(param);
@@ -768,10 +784,12 @@ static int do_suspend(struct dm_ioctl *param)
                return -ENXIO;
 
        if (param->flags & DM_SKIP_LOCKFS_FLAG)
-               do_lockfs = 0;
+               suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+       if (param->flags & DM_NOFLUSH_FLAG)
+               suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
 
        if (!dm_suspended(md))
-               r = dm_suspend(md, do_lockfs);
+               r = dm_suspend(md, suspend_flags);
 
        if (!r)
                r = __dev_status(md, param);
@@ -783,7 +801,7 @@ static int do_suspend(struct dm_ioctl *param)
 static int do_resume(struct dm_ioctl *param)
 {
        int r = 0;
-       int do_lockfs = 1;
+       unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
        struct hash_cell *hc;
        struct mapped_device *md;
        struct dm_table *new_map;
@@ -809,9 +827,11 @@ static int do_resume(struct dm_ioctl *param)
        if (new_map) {
                /* Suspend if it isn't already suspended */
                if (param->flags & DM_SKIP_LOCKFS_FLAG)
-                       do_lockfs = 0;
+                       suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+               if (param->flags & DM_NOFLUSH_FLAG)
+                       suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
                if (!dm_suspended(md))
-                       dm_suspend(md, do_lockfs);
+                       dm_suspend(md, suspend_flags);
 
                r = dm_swap_table(md, new_map);
                if (r) {
@@ -1400,8 +1420,8 @@ static int ctl_ioctl(struct inode *inode, struct file *file,
        ioctl_fn fn = NULL;
        size_t param_size;
 
-       /* only root can play with this */
-       if (!capable(CAP_SYS_ADMIN))
+       /* only root and certain contexts can play with this */
+       if (!vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_MAPPER))
                return -EACCES;
 
        if (_IOC_TYPE(command) != DM_IOCTL)