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.
13 #include <linux/module.h>
15 #include <linux/major.h>
16 #include <linux/cdev.h>
17 #include <linux/device.h>
18 #include <linux/ioctl.h>
19 #include <linux/uaccess.h>
20 #include <linux/slab.h>
21 #include <linux/bcache-ioctl.h>
23 static long bch_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
25 struct bch_ioctl_assemble arg;
27 u64 *user_devs = NULL;
32 if (copy_from_user(&arg, user_arg, sizeof(arg)))
35 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
39 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
41 if (copy_from_user(user_devs, user_arg->devs,
42 sizeof(u64) * arg.nr_devs))
45 for (i = 0; i < arg.nr_devs; i++) {
46 devs[i] = strndup_user((const char __user *)(unsigned long)
55 err = bch_register_cache_set(devs, arg.nr_devs,
56 cache_set_opts_empty(),
59 pr_err("Could not register cache set: %s", err);
67 for (i = 0; i < arg.nr_devs; i++)
73 static long bch_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
75 struct bch_ioctl_incremental arg;
79 if (copy_from_user(&arg, user_arg, sizeof(arg)))
82 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
86 err = bch_register_one(path);
90 pr_err("Could not register bcache devices: %s", err);
97 static long bch_global_ioctl(unsigned cmd, void __user *arg)
100 case BCH_IOCTL_ASSEMBLE:
101 return bch_ioctl_assemble(arg);
102 case BCH_IOCTL_INCREMENTAL:
103 return bch_ioctl_incremental(arg);
109 static long bch_ioctl_stop(struct cache_set *c)
111 bch_cache_set_stop(c);
115 static long bch_ioctl_disk_add(struct cache_set *c,
116 struct bch_ioctl_disk_add __user *user_arg)
118 struct bch_ioctl_disk_add arg;
122 if (copy_from_user(&arg, user_arg, sizeof(arg)))
125 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
129 ret = bch_cache_set_add_cache(c, path);
135 /* returns with ref on ca->ref */
136 static struct cache *bch_device_lookup(struct cache_set *c,
137 const char __user *dev)
139 struct block_device *bdev;
144 path = strndup_user(dev, PATH_MAX);
146 return ERR_PTR(-ENOMEM);
148 bdev = lookup_bdev(strim(path));
151 return ERR_CAST(bdev);
153 for_each_cache(ca, c, i)
154 if (ca->disk_sb.bdev == bdev)
163 static long bch_ioctl_disk_remove(struct cache_set *c,
164 struct bch_ioctl_disk_remove __user *user_arg)
166 struct bch_ioctl_disk_remove arg;
170 if (copy_from_user(&arg, user_arg, sizeof(arg)))
173 ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
177 ret = bch_cache_remove(ca, arg.flags & BCH_FORCE_IF_DATA_MISSING)
180 percpu_ref_put(&ca->ref);
184 static long bch_ioctl_disk_fail(struct cache_set *c,
185 struct bch_ioctl_disk_fail __user *user_arg)
187 struct bch_ioctl_disk_fail arg;
191 if (copy_from_user(&arg, user_arg, sizeof(arg)))
194 ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
198 /* XXX: failed not actually implemented yet */
199 ret = bch_cache_remove(ca, true);
201 percpu_ref_put(&ca->ref);
205 static struct cache_member *bch_uuid_lookup(struct cache_set *c, uuid_le uuid)
207 struct cache_member *mi = c->disk_mi;
210 lockdep_assert_held(&bch_register_lock);
212 for (i = 0; i < c->disk_sb.nr_in_set; i++)
213 if (!memcmp(&mi[i].uuid, &uuid, sizeof(uuid)))
219 static long bch_ioctl_disk_remove_by_uuid(struct cache_set *c,
220 struct bch_ioctl_disk_remove_by_uuid __user *user_arg)
222 struct bch_ioctl_disk_fail_by_uuid arg;
223 struct cache_member *m;
226 if (copy_from_user(&arg, user_arg, sizeof(arg)))
229 mutex_lock(&bch_register_lock);
230 if ((m = bch_uuid_lookup(c, arg.dev))) {
232 SET_CACHE_STATE(m, CACHE_FAILED);
233 bcache_write_super(c);
236 mutex_unlock(&bch_register_lock);
241 static long bch_ioctl_disk_fail_by_uuid(struct cache_set *c,
242 struct bch_ioctl_disk_fail_by_uuid __user *user_arg)
244 struct bch_ioctl_disk_fail_by_uuid arg;
245 struct cache_member *m;
248 if (copy_from_user(&arg, user_arg, sizeof(arg)))
251 mutex_lock(&bch_register_lock);
252 if ((m = bch_uuid_lookup(c, arg.dev))) {
253 SET_CACHE_STATE(m, CACHE_FAILED);
254 bcache_write_super(c);
257 mutex_unlock(&bch_register_lock);
262 static long bch_ioctl_query_uuid(struct cache_set *c,
263 struct bch_ioctl_query_uuid __user *user_arg)
265 return copy_to_user(&user_arg->uuid,
266 &c->disk_sb.user_uuid,
267 sizeof(c->disk_sb.user_uuid));
270 long bch_cache_set_ioctl(struct cache_set *c, unsigned cmd, void __user *arg)
272 /* ioctls that don't require admin cap: */
274 case BCH_IOCTL_QUERY_UUID:
275 return bch_ioctl_query_uuid(c, arg);
278 if (!capable(CAP_SYS_ADMIN))
281 /* ioctls that do require admin cap: */
286 return bch_ioctl_stop(c);
288 case BCH_IOCTL_DISK_ADD:
289 return bch_ioctl_disk_add(c, arg);
290 case BCH_IOCTL_DISK_REMOVE:
291 return bch_ioctl_disk_remove(c, arg);
292 case BCH_IOCTL_DISK_FAIL:
293 return bch_ioctl_disk_fail(c, arg);
295 case BCH_IOCTL_DISK_REMOVE_BY_UUID:
296 return bch_ioctl_disk_remove_by_uuid(c, arg);
297 case BCH_IOCTL_DISK_FAIL_BY_UUID:
298 return bch_ioctl_disk_fail_by_uuid(c, arg);
305 static long bch_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
307 struct cache_set *c = filp->private_data;
308 void __user *arg = (void __user *) v;
311 ? bch_cache_set_ioctl(c, cmd, arg)
312 : bch_global_ioctl(cmd, arg);
315 const struct file_operations bch_chardev_fops = {
316 .owner = THIS_MODULE,
317 .unlocked_ioctl = bch_chardev_ioctl,
318 .open = nonseekable_open,