2 * This file adds support for a character device /dev/bcache that is used to
3 * atomically register a list of devices, remove a device from a cache_set
4 * and add a device to a cache set.
6 * Copyright (c) 2014 Datera, Inc.
14 #include <linux/module.h>
16 #include <linux/major.h>
17 #include <linux/cdev.h>
18 #include <linux/device.h>
19 #include <linux/ioctl.h>
20 #include <linux/uaccess.h>
21 #include <linux/slab.h>
22 #include <linux/bcache-ioctl.h>
24 static long bch_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
26 struct bch_ioctl_assemble arg;
28 u64 *user_devs = NULL;
33 if (copy_from_user(&arg, user_arg, sizeof(arg)))
36 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
40 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
42 if (copy_from_user(user_devs, user_arg->devs,
43 sizeof(u64) * arg.nr_devs))
46 for (i = 0; i < arg.nr_devs; i++) {
47 devs[i] = strndup_user((const char __user *)(unsigned long)
56 err = bch_register_cache_set(devs, arg.nr_devs,
57 cache_set_opts_empty(),
60 pr_err("Could not register cache set: %s", err);
68 for (i = 0; i < arg.nr_devs; i++)
74 static long bch_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
76 struct bch_ioctl_incremental arg;
80 if (copy_from_user(&arg, user_arg, sizeof(arg)))
83 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
87 err = bch_register_one(path);
91 pr_err("Could not register bcache devices: %s", err);
98 static long bch_global_ioctl(unsigned cmd, void __user *arg)
101 case BCH_IOCTL_ASSEMBLE:
102 return bch_ioctl_assemble(arg);
103 case BCH_IOCTL_INCREMENTAL:
104 return bch_ioctl_incremental(arg);
110 static long bch_ioctl_stop(struct cache_set *c)
112 bch_cache_set_stop(c);
116 static long bch_ioctl_disk_add(struct cache_set *c,
117 struct bch_ioctl_disk_add __user *user_arg)
119 struct bch_ioctl_disk_add arg;
123 if (copy_from_user(&arg, user_arg, sizeof(arg)))
126 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
130 ret = bch_cache_set_add_cache(c, path);
136 /* returns with ref on ca->ref */
137 static struct cache *bch_device_lookup(struct cache_set *c,
138 const char __user *dev)
140 struct block_device *bdev;
145 path = strndup_user(dev, PATH_MAX);
147 return ERR_PTR(-ENOMEM);
149 bdev = lookup_bdev(strim(path));
152 return ERR_CAST(bdev);
154 for_each_cache(ca, c, i)
155 if (ca->disk_sb.bdev == bdev)
164 static long bch_ioctl_disk_remove(struct cache_set *c,
165 struct bch_ioctl_disk_remove __user *user_arg)
167 struct bch_ioctl_disk_remove arg;
171 if (copy_from_user(&arg, user_arg, sizeof(arg)))
174 ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
178 ret = bch_cache_remove(ca, arg.flags & BCH_FORCE_IF_DATA_MISSING)
181 percpu_ref_put(&ca->ref);
185 static long bch_ioctl_disk_fail(struct cache_set *c,
186 struct bch_ioctl_disk_fail __user *user_arg)
188 struct bch_ioctl_disk_fail arg;
192 if (copy_from_user(&arg, user_arg, sizeof(arg)))
195 ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
199 /* XXX: failed not actually implemented yet */
200 ret = bch_cache_remove(ca, true);
202 percpu_ref_put(&ca->ref);
206 static struct bch_member *bch_uuid_lookup(struct cache_set *c, uuid_le uuid)
208 struct bch_sb_field_members *mi = bch_sb_get_members(c->disk_sb);
211 lockdep_assert_held(&c->sb_lock);
213 for (i = 0; i < c->disk_sb->nr_devices; i++)
214 if (!memcmp(&mi->members[i].uuid, &uuid, sizeof(uuid)))
215 return &mi->members[i];
220 static long bch_ioctl_disk_remove_by_uuid(struct cache_set *c,
221 struct bch_ioctl_disk_remove_by_uuid __user *user_arg)
223 struct bch_ioctl_disk_fail_by_uuid arg;
224 struct bch_member *m;
227 if (copy_from_user(&arg, user_arg, sizeof(arg)))
230 mutex_lock(&c->sb_lock);
231 if ((m = bch_uuid_lookup(c, arg.dev))) {
233 SET_BCH_MEMBER_STATE(m, BCH_MEMBER_STATE_FAILED);
237 mutex_unlock(&c->sb_lock);
242 static long bch_ioctl_disk_fail_by_uuid(struct cache_set *c,
243 struct bch_ioctl_disk_fail_by_uuid __user *user_arg)
245 struct bch_ioctl_disk_fail_by_uuid arg;
246 struct bch_member *m;
249 if (copy_from_user(&arg, user_arg, sizeof(arg)))
252 mutex_lock(&c->sb_lock);
253 if ((m = bch_uuid_lookup(c, arg.dev))) {
254 SET_BCH_MEMBER_STATE(m, BCH_MEMBER_STATE_FAILED);
258 mutex_unlock(&c->sb_lock);
263 static long bch_ioctl_query_uuid(struct cache_set *c,
264 struct bch_ioctl_query_uuid __user *user_arg)
266 return copy_to_user(&user_arg->uuid,
268 sizeof(c->sb.user_uuid));
271 long bch_cache_set_ioctl(struct cache_set *c, unsigned cmd, void __user *arg)
273 /* ioctls that don't require admin cap: */
275 case BCH_IOCTL_QUERY_UUID:
276 return bch_ioctl_query_uuid(c, arg);
279 if (!capable(CAP_SYS_ADMIN))
282 /* ioctls that do require admin cap: */
287 return bch_ioctl_stop(c);
289 case BCH_IOCTL_DISK_ADD:
290 return bch_ioctl_disk_add(c, arg);
291 case BCH_IOCTL_DISK_REMOVE:
292 return bch_ioctl_disk_remove(c, arg);
293 case BCH_IOCTL_DISK_FAIL:
294 return bch_ioctl_disk_fail(c, arg);
296 case BCH_IOCTL_DISK_REMOVE_BY_UUID:
297 return bch_ioctl_disk_remove_by_uuid(c, arg);
298 case BCH_IOCTL_DISK_FAIL_BY_UUID:
299 return bch_ioctl_disk_fail_by_uuid(c, arg);
306 static long bch_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
308 struct cache_set *c = filp->private_data;
309 void __user *arg = (void __user *) v;
312 ? bch_cache_set_ioctl(c, cmd, arg)
313 : bch_global_ioctl(cmd, arg);
316 const struct file_operations bch_chardev_fops = {
317 .owner = THIS_MODULE,
318 .unlocked_ioctl = bch_chardev_ioctl,
319 .open = nonseekable_open,