Blame view

fs/fuse/cuse.c 15.8 KB
55716d264   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
151060ac1   Tejun Heo   CUSE: implement C...
2
3
4
5
6
7
  /*
   * CUSE: Character device in Userspace
   *
   * Copyright (C) 2008-2009  SUSE Linux Products GmbH
   * Copyright (C) 2008-2009  Tejun Heo <tj@kernel.org>
   *
151060ac1   Tejun Heo   CUSE: implement C...
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
   * CUSE enables character devices to be implemented from userland much
   * like FUSE allows filesystems.  On initialization /dev/cuse is
   * created.  By opening the file and replying to the CUSE_INIT request
   * userland CUSE server can create a character device.  After that the
   * operation is very similar to FUSE.
   *
   * A CUSE instance involves the following objects.
   *
   * cuse_conn	: contains fuse_conn and serves as bonding structure
   * channel	: file handle connected to the userland CUSE server
   * cdev		: the implemented character device
   * dev		: generic device for cdev
   *
   * Note that 'channel' is what 'dev' is in FUSE.  As CUSE deals with
   * devices, it's called 'channel' to reduce confusion.
   *
   * channel determines when the character device dies.  When channel is
   * closed, everything begins to destruct.  The cuse_conn is taken off
   * the lookup table preventing further access from cdev, cdev and
   * generic device are removed and the base reference of cuse_conn is
   * put.
   *
   * On each open, the matching cuse_conn is looked up and if found an
   * additional reference is taken which is released when the file is
   * closed.
   */
f2294482f   Kirill Smelkov   fuse: convert pri...
34
  #define pr_fmt(fmt) "CUSE: " fmt
151060ac1   Tejun Heo   CUSE: implement C...
35
36
37
38
39
40
41
42
43
44
45
  #include <linux/fuse.h>
  #include <linux/cdev.h>
  #include <linux/device.h>
  #include <linux/file.h>
  #include <linux/fs.h>
  #include <linux/kdev_t.h>
  #include <linux/kthread.h>
  #include <linux/list.h>
  #include <linux/magic.h>
  #include <linux/miscdevice.h>
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
46
  #include <linux/slab.h>
151060ac1   Tejun Heo   CUSE: implement C...
47
  #include <linux/stat.h>
143cb494c   Paul Gortmaker   fs: add module.h ...
48
  #include <linux/module.h>
e2e40f2c1   Christoph Hellwig   fs: move struct k...
49
  #include <linux/uio.h>
8cb08329b   Eric W. Biederman   fuse: Support fus...
50
  #include <linux/user_namespace.h>
151060ac1   Tejun Heo   CUSE: implement C...
51
52
53
54
55
56
57
  
  #include "fuse_i.h"
  
  #define CUSE_CONNTBL_LEN	64
  
  struct cuse_conn {
  	struct list_head	list;	/* linked on cuse_conntbl */
fcee216be   Max Reitz   fuse: split fuse_...
58
  	struct fuse_mount	fm;	/* Dummy mount referencing fc */
151060ac1   Tejun Heo   CUSE: implement C...
59
60
61
62
63
64
65
  	struct fuse_conn	fc;	/* fuse connection */
  	struct cdev		*cdev;	/* associated character device */
  	struct device		*dev;	/* device representing @cdev */
  
  	/* init parameters, set once during initialization */
  	bool			unrestricted_ioctl;
  };
8ce03fd76   David Herrmann   cuse: use mutex a...
66
  static DEFINE_MUTEX(cuse_lock);		/* protects registration */
151060ac1   Tejun Heo   CUSE: implement C...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  static struct list_head cuse_conntbl[CUSE_CONNTBL_LEN];
  static struct class *cuse_class;
  
  static struct cuse_conn *fc_to_cc(struct fuse_conn *fc)
  {
  	return container_of(fc, struct cuse_conn, fc);
  }
  
  static struct list_head *cuse_conntbl_head(dev_t devt)
  {
  	return &cuse_conntbl[(MAJOR(devt) + MINOR(devt)) % CUSE_CONNTBL_LEN];
  }
  
  
  /**************************************************************************
   * CUSE frontend operations
   *
   * These are file operations for the character device.
   *
   * On open, CUSE opens a file from the FUSE mnt and stores it to
   * private_data of the open file.  All other ops call FUSE ops on the
   * FUSE file.
   */
cfa86a741   Al Viro   cuse: switch to i...
90
  static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
151060ac1   Tejun Heo   CUSE: implement C...
91
  {
e1c0eecba   Miklos Szeredi   fuse: honor iocb ...
92
  	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb);
151060ac1   Tejun Heo   CUSE: implement C...
93
  	loff_t pos = 0;
cfa86a741   Al Viro   cuse: switch to i...
94
  	return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE);
151060ac1   Tejun Heo   CUSE: implement C...
95
  }
cfa86a741   Al Viro   cuse: switch to i...
96
  static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
151060ac1   Tejun Heo   CUSE: implement C...
97
  {
e1c0eecba   Miklos Szeredi   fuse: honor iocb ...
98
  	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb);
151060ac1   Tejun Heo   CUSE: implement C...
99
100
101
102
103
  	loff_t pos = 0;
  	/*
  	 * No locking or generic_write_checks(), the server is
  	 * responsible for locking and sanity checks.
  	 */
cfa86a741   Al Viro   cuse: switch to i...
104
  	return fuse_direct_io(&io, from, &pos,
ea8cd3339   Pavel Emelyanov   fuse: Fix O_DIREC...
105
  			      FUSE_DIO_WRITE | FUSE_DIO_CUSE);
151060ac1   Tejun Heo   CUSE: implement C...
106
107
108
109
110
111
112
113
114
  }
  
  static int cuse_open(struct inode *inode, struct file *file)
  {
  	dev_t devt = inode->i_cdev->dev;
  	struct cuse_conn *cc = NULL, *pos;
  	int rc;
  
  	/* look up and get the connection */
8ce03fd76   David Herrmann   cuse: use mutex a...
115
  	mutex_lock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
116
117
118
119
120
121
  	list_for_each_entry(pos, cuse_conntbl_head(devt), list)
  		if (pos->dev->devt == devt) {
  			fuse_conn_get(&pos->fc);
  			cc = pos;
  			break;
  		}
8ce03fd76   David Herrmann   cuse: use mutex a...
122
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
123
124
125
126
127
128
129
130
131
  
  	/* dead? */
  	if (!cc)
  		return -ENODEV;
  
  	/*
  	 * Generic permission check is already done against the chrdev
  	 * file, proceed to open.
  	 */
fcee216be   Max Reitz   fuse: split fuse_...
132
  	rc = fuse_do_open(&cc->fm, 0, file, 0);
151060ac1   Tejun Heo   CUSE: implement C...
133
134
135
136
137
138
139
140
  	if (rc)
  		fuse_conn_put(&cc->fc);
  	return rc;
  }
  
  static int cuse_release(struct inode *inode, struct file *file)
  {
  	struct fuse_file *ff = file->private_data;
fcee216be   Max Reitz   fuse: split fuse_...
141
  	struct fuse_mount *fm = ff->fm;
151060ac1   Tejun Heo   CUSE: implement C...
142

56d250ef9   Miklos Szeredi   cuse: fix broken ...
143
  	fuse_sync_release(NULL, ff, file->f_flags);
fcee216be   Max Reitz   fuse: split fuse_...
144
  	fuse_conn_put(fm->fc);
151060ac1   Tejun Heo   CUSE: implement C...
145
146
147
148
149
150
151
152
  
  	return 0;
  }
  
  static long cuse_file_ioctl(struct file *file, unsigned int cmd,
  			    unsigned long arg)
  {
  	struct fuse_file *ff = file->private_data;
fcee216be   Max Reitz   fuse: split fuse_...
153
  	struct cuse_conn *cc = fc_to_cc(ff->fm->fc);
151060ac1   Tejun Heo   CUSE: implement C...
154
155
156
157
158
159
160
161
162
163
164
165
  	unsigned int flags = 0;
  
  	if (cc->unrestricted_ioctl)
  		flags |= FUSE_IOCTL_UNRESTRICTED;
  
  	return fuse_do_ioctl(file, cmd, arg, flags);
  }
  
  static long cuse_file_compat_ioctl(struct file *file, unsigned int cmd,
  				   unsigned long arg)
  {
  	struct fuse_file *ff = file->private_data;
fcee216be   Max Reitz   fuse: split fuse_...
166
  	struct cuse_conn *cc = fc_to_cc(ff->fm->fc);
151060ac1   Tejun Heo   CUSE: implement C...
167
168
169
170
171
172
173
174
175
176
  	unsigned int flags = FUSE_IOCTL_COMPAT;
  
  	if (cc->unrestricted_ioctl)
  		flags |= FUSE_IOCTL_UNRESTRICTED;
  
  	return fuse_do_ioctl(file, cmd, arg, flags);
  }
  
  static const struct file_operations cuse_frontend_fops = {
  	.owner			= THIS_MODULE,
cfa86a741   Al Viro   cuse: switch to i...
177
178
  	.read_iter		= cuse_read_iter,
  	.write_iter		= cuse_write_iter,
151060ac1   Tejun Heo   CUSE: implement C...
179
180
181
182
183
  	.open			= cuse_open,
  	.release		= cuse_release,
  	.unlocked_ioctl		= cuse_file_ioctl,
  	.compat_ioctl		= cuse_file_compat_ioctl,
  	.poll			= fuse_file_poll,
6038f373a   Arnd Bergmann   llseek: automatic...
184
  	.llseek		= noop_llseek,
151060ac1   Tejun Heo   CUSE: implement C...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  };
  
  
  /**************************************************************************
   * CUSE channel initialization and destruction
   */
  
  struct cuse_devinfo {
  	const char		*name;
  };
  
  /**
   * cuse_parse_one - parse one key=value pair
   * @pp: i/o parameter for the current position
   * @end: points to one past the end of the packed string
   * @keyp: out parameter for key
   * @valp: out parameter for value
   *
   * *@pp points to packed strings - "key0=val0\0key1=val1\0" which ends
   * at @end - 1.  This function parses one pair and set *@keyp to the
   * start of the key and *@valp to the start of the value.  Note that
   * the original string is modified such that the key string is
   * terminated with '\0'.  *@pp is updated to point to the next string.
   *
   * RETURNS:
   * 1 on successful parse, 0 on EOF, -errno on failure.
   */
  static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
  {
  	char *p = *pp;
  	char *key, *val;
  
  	while (p < end && *p == '\0')
  		p++;
  	if (p == end)
  		return 0;
  
  	if (end[-1] != '\0') {
f2294482f   Kirill Smelkov   fuse: convert pri...
223
224
  		pr_err("info not properly terminated
  ");
151060ac1   Tejun Heo   CUSE: implement C...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  		return -EINVAL;
  	}
  
  	key = val = p;
  	p += strlen(p);
  
  	if (valp) {
  		strsep(&val, "=");
  		if (!val)
  			val = key + strlen(key);
  		key = strstrip(key);
  		val = strstrip(val);
  	} else
  		key = strstrip(key);
  
  	if (!strlen(key)) {
f2294482f   Kirill Smelkov   fuse: convert pri...
241
242
  		pr_err("zero length info key specified
  ");
151060ac1   Tejun Heo   CUSE: implement C...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  		return -EINVAL;
  	}
  
  	*pp = p;
  	*keyp = key;
  	if (valp)
  		*valp = val;
  
  	return 1;
  }
  
  /**
   * cuse_parse_dev_info - parse device info
   * @p: device info string
   * @len: length of device info string
   * @devinfo: out parameter for parsed device info
   *
   * Parse @p to extract device info and store it into @devinfo.  String
   * pointed to by @p is modified by parsing and @devinfo points into
   * them, so @p shouldn't be freed while @devinfo is in use.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
  {
  	char *end = p + len;
3f649ab72   Kees Cook   treewide: Remove ...
270
  	char *key, *val;
151060ac1   Tejun Heo   CUSE: implement C...
271
272
273
274
275
276
277
278
279
280
281
  	int rc;
  
  	while (true) {
  		rc = cuse_parse_one(&p, end, &key, &val);
  		if (rc < 0)
  			return rc;
  		if (!rc)
  			break;
  		if (strcmp(key, "DEVNAME") == 0)
  			devinfo->name = val;
  		else
f2294482f   Kirill Smelkov   fuse: convert pri...
282
283
  			pr_warn("unknown device info \"%s\"
  ", key);
151060ac1   Tejun Heo   CUSE: implement C...
284
285
286
  	}
  
  	if (!devinfo->name || !strlen(devinfo->name)) {
f2294482f   Kirill Smelkov   fuse: convert pri...
287
288
  		pr_err("DEVNAME unspecified
  ");
151060ac1   Tejun Heo   CUSE: implement C...
289
290
291
292
293
294
295
296
297
298
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static void cuse_gendev_release(struct device *dev)
  {
  	kfree(dev);
  }
b50ef7c52   Miklos Szeredi   cuse: convert ini...
299
300
301
302
303
304
305
  struct cuse_init_args {
  	struct fuse_args_pages ap;
  	struct cuse_init_in in;
  	struct cuse_init_out out;
  	struct page *page;
  	struct fuse_page_desc desc;
  };
151060ac1   Tejun Heo   CUSE: implement C...
306
307
308
309
310
311
312
  /**
   * cuse_process_init_reply - finish initializing CUSE channel
   *
   * This function creates the character device and sets up all the
   * required data structures for it.  Please read the comment at the
   * top of this file for high level overview.
   */
fcee216be   Max Reitz   fuse: split fuse_...
313
  static void cuse_process_init_reply(struct fuse_mount *fm,
b50ef7c52   Miklos Szeredi   cuse: convert ini...
314
  				    struct fuse_args *args, int error)
151060ac1   Tejun Heo   CUSE: implement C...
315
  {
fcee216be   Max Reitz   fuse: split fuse_...
316
  	struct fuse_conn *fc = fm->fc;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
317
318
  	struct cuse_init_args *ia = container_of(args, typeof(*ia), ap.args);
  	struct fuse_args_pages *ap = &ia->ap;
30783587b   David Herrmann   cuse: do not regi...
319
  	struct cuse_conn *cc = fc_to_cc(fc), *pos;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
320
321
  	struct cuse_init_out *arg = &ia->out;
  	struct page *page = ap->pages[0];
151060ac1   Tejun Heo   CUSE: implement C...
322
323
324
325
  	struct cuse_devinfo devinfo = { };
  	struct device *dev;
  	struct cdev *cdev;
  	dev_t devt;
30783587b   David Herrmann   cuse: do not regi...
326
  	int rc, i;
151060ac1   Tejun Heo   CUSE: implement C...
327

b50ef7c52   Miklos Szeredi   cuse: convert ini...
328
  	if (error || arg->major != FUSE_KERNEL_VERSION || arg->minor < 11)
151060ac1   Tejun Heo   CUSE: implement C...
329
  		goto err;
151060ac1   Tejun Heo   CUSE: implement C...
330
331
332
333
334
335
336
  
  	fc->minor = arg->minor;
  	fc->max_read = max_t(unsigned, arg->max_read, 4096);
  	fc->max_write = max_t(unsigned, arg->max_write, 4096);
  
  	/* parse init reply */
  	cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
337
  	rc = cuse_parse_devinfo(page_address(page), ap->args.out_args[1].size,
151060ac1   Tejun Heo   CUSE: implement C...
338
339
340
341
342
343
344
345
346
347
348
  				&devinfo);
  	if (rc)
  		goto err;
  
  	/* determine and reserve devt */
  	devt = MKDEV(arg->dev_major, arg->dev_minor);
  	if (!MAJOR(devt))
  		rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
  	else
  		rc = register_chrdev_region(devt, 1, devinfo.name);
  	if (rc) {
f2294482f   Kirill Smelkov   fuse: convert pri...
349
350
  		pr_err("failed to register chrdev region
  ");
151060ac1   Tejun Heo   CUSE: implement C...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  		goto err;
  	}
  
  	/* devt determined, create device */
  	rc = -ENOMEM;
  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  	if (!dev)
  		goto err_region;
  
  	device_initialize(dev);
  	dev_set_uevent_suppress(dev, 1);
  	dev->class = cuse_class;
  	dev->devt = devt;
  	dev->release = cuse_gendev_release;
  	dev_set_drvdata(dev, cc);
  	dev_set_name(dev, "%s", devinfo.name);
30783587b   David Herrmann   cuse: do not regi...
367
368
369
370
371
372
373
374
  	mutex_lock(&cuse_lock);
  
  	/* make sure the device-name is unique */
  	for (i = 0; i < CUSE_CONNTBL_LEN; ++i) {
  		list_for_each_entry(pos, &cuse_conntbl[i], list)
  			if (!strcmp(dev_name(pos->dev), dev_name(dev)))
  				goto err_unlock;
  	}
151060ac1   Tejun Heo   CUSE: implement C...
375
376
  	rc = device_add(dev);
  	if (rc)
30783587b   David Herrmann   cuse: do not regi...
377
  		goto err_unlock;
151060ac1   Tejun Heo   CUSE: implement C...
378
379
380
381
382
  
  	/* register cdev */
  	rc = -ENOMEM;
  	cdev = cdev_alloc();
  	if (!cdev)
30783587b   David Herrmann   cuse: do not regi...
383
  		goto err_unlock;
151060ac1   Tejun Heo   CUSE: implement C...
384
385
386
387
388
389
390
391
392
393
394
395
  
  	cdev->owner = THIS_MODULE;
  	cdev->ops = &cuse_frontend_fops;
  
  	rc = cdev_add(cdev, devt, 1);
  	if (rc)
  		goto err_cdev;
  
  	cc->dev = dev;
  	cc->cdev = cdev;
  
  	/* make the device available */
151060ac1   Tejun Heo   CUSE: implement C...
396
  	list_add(&cc->list, cuse_conntbl_head(devt));
8ce03fd76   David Herrmann   cuse: use mutex a...
397
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
398
399
400
401
402
  
  	/* announce device availability */
  	dev_set_uevent_suppress(dev, 0);
  	kobject_uevent(&dev->kobj, KOBJ_ADD);
  out:
b50ef7c52   Miklos Szeredi   cuse: convert ini...
403
  	kfree(ia);
151060ac1   Tejun Heo   CUSE: implement C...
404
405
406
407
408
  	__free_page(page);
  	return;
  
  err_cdev:
  	cdev_del(cdev);
30783587b   David Herrmann   cuse: do not regi...
409
410
  err_unlock:
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
411
412
413
414
  	put_device(dev);
  err_region:
  	unregister_chrdev_region(devt, 1);
  err:
eb98e3bdf   Miklos Szeredi   fuse: clean up ab...
415
  	fuse_abort_conn(fc);
151060ac1   Tejun Heo   CUSE: implement C...
416
417
418
419
420
421
  	goto out;
  }
  
  static int cuse_send_init(struct cuse_conn *cc)
  {
  	int rc;
151060ac1   Tejun Heo   CUSE: implement C...
422
  	struct page *page;
fcee216be   Max Reitz   fuse: split fuse_...
423
  	struct fuse_mount *fm = &cc->fm;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
424
425
  	struct cuse_init_args *ia;
  	struct fuse_args_pages *ap;
151060ac1   Tejun Heo   CUSE: implement C...
426
427
  
  	BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
151060ac1   Tejun Heo   CUSE: implement C...
428
429
430
  	rc = -ENOMEM;
  	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
  	if (!page)
b50ef7c52   Miklos Szeredi   cuse: convert ini...
431
  		goto err;
151060ac1   Tejun Heo   CUSE: implement C...
432

b50ef7c52   Miklos Szeredi   cuse: convert ini...
433
434
  	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
  	if (!ia)
07d5f69b4   Miklos Szeredi   fuse: reduce size...
435
  		goto err_free_page;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
436
437
438
439
440
441
442
443
444
445
446
447
  	ap = &ia->ap;
  	ia->in.major = FUSE_KERNEL_VERSION;
  	ia->in.minor = FUSE_KERNEL_MINOR_VERSION;
  	ia->in.flags |= CUSE_UNRESTRICTED_IOCTL;
  	ap->args.opcode = CUSE_INIT;
  	ap->args.in_numargs = 1;
  	ap->args.in_args[0].size = sizeof(ia->in);
  	ap->args.in_args[0].value = &ia->in;
  	ap->args.out_numargs = 2;
  	ap->args.out_args[0].size = sizeof(ia->out);
  	ap->args.out_args[0].value = &ia->out;
  	ap->args.out_args[1].size = CUSE_INIT_INFO_MAX;
cabdb4fa2   zhengbin   fuse: use true,fa...
448
449
  	ap->args.out_argvar = true;
  	ap->args.out_pages = true;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
450
451
452
453
454
455
  	ap->num_pages = 1;
  	ap->pages = &ia->page;
  	ap->descs = &ia->desc;
  	ia->page = page;
  	ia->desc.length = ap->args.out_args[1].size;
  	ap->args.end = cuse_process_init_reply;
fcee216be   Max Reitz   fuse: split fuse_...
456
  	rc = fuse_simple_background(fm, &ap->args, GFP_KERNEL);
b50ef7c52   Miklos Szeredi   cuse: convert ini...
457
458
  	if (rc) {
  		kfree(ia);
07d5f69b4   Miklos Szeredi   fuse: reduce size...
459
  err_free_page:
b50ef7c52   Miklos Szeredi   cuse: convert ini...
460
461
  		__free_page(page);
  	}
151060ac1   Tejun Heo   CUSE: implement C...
462
463
464
465
466
467
468
  err:
  	return rc;
  }
  
  static void cuse_fc_release(struct fuse_conn *fc)
  {
  	struct cuse_conn *cc = fc_to_cc(fc);
dd3e2c55a   Al Viro   fuse: rcu-delay f...
469
  	kfree_rcu(cc, fc.rcu);
151060ac1   Tejun Heo   CUSE: implement C...
470
471
472
473
474
475
476
477
  }
  
  /**
   * cuse_channel_open - open method for /dev/cuse
   * @inode: inode for /dev/cuse
   * @file: file struct being opened
   *
   * Userland CUSE server can create a CUSE device by opening /dev/cuse
8272f4c9c   Paul Bolle   fuse/cuse: fix co...
478
   * and replying to the initialization request kernel sends.  This
151060ac1   Tejun Heo   CUSE: implement C...
479
480
481
482
483
484
485
486
487
488
   * function is responsible for handling CUSE device initialization.
   * Because the fd opened by this function is used during
   * initialization, this function only creates cuse_conn and sends
   * init.  The rest is delegated to a kthread.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  static int cuse_channel_open(struct inode *inode, struct file *file)
  {
cc080e9e9   Miklos Szeredi   fuse: introduce p...
489
  	struct fuse_dev *fud;
151060ac1   Tejun Heo   CUSE: implement C...
490
491
492
493
494
495
496
  	struct cuse_conn *cc;
  	int rc;
  
  	/* set up cuse_conn */
  	cc = kzalloc(sizeof(*cc), GFP_KERNEL);
  	if (!cc)
  		return -ENOMEM;
8cb08329b   Eric W. Biederman   fuse: Support fus...
497
498
499
500
  	/*
  	 * Limit the cuse channel to requests that can
  	 * be represented in file->f_cred->user_ns.
  	 */
fcee216be   Max Reitz   fuse: split fuse_...
501
502
  	fuse_conn_init(&cc->fc, &cc->fm, file->f_cred->user_ns,
  		       &fuse_dev_fiq_ops, NULL);
151060ac1   Tejun Heo   CUSE: implement C...
503

0cd1eb9a4   Vivek Goyal   fuse: separate fu...
504
  	fud = fuse_dev_alloc_install(&cc->fc);
cc080e9e9   Miklos Szeredi   fuse: introduce p...
505
506
507
508
  	if (!fud) {
  		kfree(cc);
  		return -ENOMEM;
  	}
151060ac1   Tejun Heo   CUSE: implement C...
509
510
  	INIT_LIST_HEAD(&cc->list);
  	cc->fc.release = cuse_fc_release;
796523fb2   Maxim Patlasov   fuse: add flag fc...
511
  	cc->fc.initialized = 1;
151060ac1   Tejun Heo   CUSE: implement C...
512
513
  	rc = cuse_send_init(cc);
  	if (rc) {
cc080e9e9   Miklos Szeredi   fuse: introduce p...
514
  		fuse_dev_free(fud);
9ad09b197   zhengbin   fuse: fix memleak...
515
  		fuse_conn_put(&cc->fc);
151060ac1   Tejun Heo   CUSE: implement C...
516
517
  		return rc;
  	}
cc080e9e9   Miklos Szeredi   fuse: introduce p...
518
  	file->private_data = fud;
151060ac1   Tejun Heo   CUSE: implement C...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  
  	return 0;
  }
  
  /**
   * cuse_channel_release - release method for /dev/cuse
   * @inode: inode for /dev/cuse
   * @file: file struct being closed
   *
   * Disconnect the channel, deregister CUSE device and initiate
   * destruction by putting the default reference.
   *
   * RETURNS:
   * 0 on success, -errno on failure.
   */
  static int cuse_channel_release(struct inode *inode, struct file *file)
  {
cc080e9e9   Miklos Szeredi   fuse: introduce p...
536
537
  	struct fuse_dev *fud = file->private_data;
  	struct cuse_conn *cc = fc_to_cc(fud->fc);
151060ac1   Tejun Heo   CUSE: implement C...
538
539
540
  	int rc;
  
  	/* remove from the conntbl, no more access from this point on */
8ce03fd76   David Herrmann   cuse: use mutex a...
541
  	mutex_lock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
542
  	list_del_init(&cc->list);
8ce03fd76   David Herrmann   cuse: use mutex a...
543
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
544
545
546
547
548
549
550
551
  
  	/* remove device */
  	if (cc->dev)
  		device_unregister(cc->dev);
  	if (cc->cdev) {
  		unregister_chrdev_region(cc->cdev->dev, 1);
  		cdev_del(cc->cdev);
  	}
2c5816b4b   Miklos Szeredi   cuse: fix memory ...
552
553
  	/* Base reference is now owned by "fud" */
  	fuse_conn_put(&cc->fc);
151060ac1   Tejun Heo   CUSE: implement C...
554

151060ac1   Tejun Heo   CUSE: implement C...
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
  	rc = fuse_dev_release(inode, file);	/* puts the base reference */
  
  	return rc;
  }
  
  static struct file_operations cuse_channel_fops; /* initialized during init */
  
  
  /**************************************************************************
   * Misc stuff and module initializatiion
   *
   * CUSE exports the same set of attributes to sysfs as fusectl.
   */
  
  static ssize_t cuse_class_waiting_show(struct device *dev,
  				       struct device_attribute *attr, char *buf)
  {
  	struct cuse_conn *cc = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%d
  ", atomic_read(&cc->fc.num_waiting));
  }
58f86cc89   Rusty Russell   VERIFY_OCTAL_PERM...
577
  static DEVICE_ATTR(waiting, 0400, cuse_class_waiting_show, NULL);
151060ac1   Tejun Heo   CUSE: implement C...
578
579
580
581
582
583
  
  static ssize_t cuse_class_abort_store(struct device *dev,
  				      struct device_attribute *attr,
  				      const char *buf, size_t count)
  {
  	struct cuse_conn *cc = dev_get_drvdata(dev);
eb98e3bdf   Miklos Szeredi   fuse: clean up ab...
584
  	fuse_abort_conn(&cc->fc);
151060ac1   Tejun Heo   CUSE: implement C...
585
586
  	return count;
  }
58f86cc89   Rusty Russell   VERIFY_OCTAL_PERM...
587
  static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
151060ac1   Tejun Heo   CUSE: implement C...
588

4183fb950   Greg Kroah-Hartman   cuse: convert cla...
589
590
591
592
  static struct attribute *cuse_class_dev_attrs[] = {
  	&dev_attr_waiting.attr,
  	&dev_attr_abort.attr,
  	NULL,
151060ac1   Tejun Heo   CUSE: implement C...
593
  };
4183fb950   Greg Kroah-Hartman   cuse: convert cla...
594
  ATTRIBUTE_GROUPS(cuse_class_dev);
151060ac1   Tejun Heo   CUSE: implement C...
595
596
  
  static struct miscdevice cuse_miscdev = {
cb2ffb26e   Tom Gundersen   cuse: add fix min...
597
  	.minor		= CUSE_MINOR,
151060ac1   Tejun Heo   CUSE: implement C...
598
599
600
  	.name		= "cuse",
  	.fops		= &cuse_channel_fops,
  };
cb2ffb26e   Tom Gundersen   cuse: add fix min...
601
602
  MODULE_ALIAS_MISCDEV(CUSE_MINOR);
  MODULE_ALIAS("devname:cuse");
151060ac1   Tejun Heo   CUSE: implement C...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  static int __init cuse_init(void)
  {
  	int i, rc;
  
  	/* init conntbl */
  	for (i = 0; i < CUSE_CONNTBL_LEN; i++)
  		INIT_LIST_HEAD(&cuse_conntbl[i]);
  
  	/* inherit and extend fuse_dev_operations */
  	cuse_channel_fops		= fuse_dev_operations;
  	cuse_channel_fops.owner		= THIS_MODULE;
  	cuse_channel_fops.open		= cuse_channel_open;
  	cuse_channel_fops.release	= cuse_channel_release;
  
  	cuse_class = class_create(THIS_MODULE, "cuse");
  	if (IS_ERR(cuse_class))
  		return PTR_ERR(cuse_class);
4183fb950   Greg Kroah-Hartman   cuse: convert cla...
620
  	cuse_class->dev_groups = cuse_class_dev_groups;
151060ac1   Tejun Heo   CUSE: implement C...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  
  	rc = misc_register(&cuse_miscdev);
  	if (rc) {
  		class_destroy(cuse_class);
  		return rc;
  	}
  
  	return 0;
  }
  
  static void __exit cuse_exit(void)
  {
  	misc_deregister(&cuse_miscdev);
  	class_destroy(cuse_class);
  }
  
  module_init(cuse_init);
  module_exit(cuse_exit);
  
  MODULE_AUTHOR("Tejun Heo <tj@kernel.org>");
  MODULE_DESCRIPTION("Character device in Userspace");
  MODULE_LICENSE("GPL");