Blame view

fs/fuse/cuse.c 15.7 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
58
59
60
61
62
63
64
  
  #include "fuse_i.h"
  
  #define CUSE_CONNTBL_LEN	64
  
  struct cuse_conn {
  	struct list_head	list;	/* linked on cuse_conntbl */
  	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...
65
  static DEFINE_MUTEX(cuse_lock);		/* protects registration */
151060ac1   Tejun Heo   CUSE: implement C...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  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...
89
  static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
151060ac1   Tejun Heo   CUSE: implement C...
90
  {
e1c0eecba   Miklos Szeredi   fuse: honor iocb ...
91
  	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb);
151060ac1   Tejun Heo   CUSE: implement C...
92
  	loff_t pos = 0;
cfa86a741   Al Viro   cuse: switch to i...
93
  	return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE);
151060ac1   Tejun Heo   CUSE: implement C...
94
  }
cfa86a741   Al Viro   cuse: switch to i...
95
  static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
151060ac1   Tejun Heo   CUSE: implement C...
96
  {
e1c0eecba   Miklos Szeredi   fuse: honor iocb ...
97
  	struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb);
151060ac1   Tejun Heo   CUSE: implement C...
98
99
100
101
102
  	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...
103
  	return fuse_direct_io(&io, from, &pos,
ea8cd3339   Pavel Emelyanov   fuse: Fix O_DIREC...
104
  			      FUSE_DIO_WRITE | FUSE_DIO_CUSE);
151060ac1   Tejun Heo   CUSE: implement C...
105
106
107
108
109
110
111
112
113
  }
  
  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...
114
  	mutex_lock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
115
116
117
118
119
120
  	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...
121
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  
  	/* dead? */
  	if (!cc)
  		return -ENODEV;
  
  	/*
  	 * Generic permission check is already done against the chrdev
  	 * file, proceed to open.
  	 */
  	rc = fuse_do_open(&cc->fc, 0, file, 0);
  	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;
  	struct fuse_conn *fc = ff->fc;
56d250ef9   Miklos Szeredi   cuse: fix broken ...
141
  	fuse_sync_release(NULL, ff, file->f_flags);
151060ac1   Tejun Heo   CUSE: implement C...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	fuse_conn_put(fc);
  
  	return 0;
  }
  
  static long cuse_file_ioctl(struct file *file, unsigned int cmd,
  			    unsigned long arg)
  {
  	struct fuse_file *ff = file->private_data;
  	struct cuse_conn *cc = fc_to_cc(ff->fc);
  	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;
  	struct cuse_conn *cc = fc_to_cc(ff->fc);
  	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...
175
176
  	.read_iter		= cuse_read_iter,
  	.write_iter		= cuse_write_iter,
151060ac1   Tejun Heo   CUSE: implement C...
177
178
179
180
181
  	.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...
182
  	.llseek		= noop_llseek,
151060ac1   Tejun Heo   CUSE: implement C...
183
184
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
  };
  
  
  /**************************************************************************
   * 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...
221
222
  		pr_err("info not properly terminated
  ");
151060ac1   Tejun Heo   CUSE: implement C...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  		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...
239
240
  		pr_err("zero length info key specified
  ");
151060ac1   Tejun Heo   CUSE: implement C...
241
242
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
  		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;
e2560362c   Miklos Szeredi   cuse: fix uniniti...
268
  	char *uninitialized_var(key), *uninitialized_var(val);
151060ac1   Tejun Heo   CUSE: implement C...
269
270
271
272
273
274
275
276
277
278
279
  	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...
280
281
  			pr_warn("unknown device info \"%s\"
  ", key);
151060ac1   Tejun Heo   CUSE: implement C...
282
283
284
  	}
  
  	if (!devinfo->name || !strlen(devinfo->name)) {
f2294482f   Kirill Smelkov   fuse: convert pri...
285
286
  		pr_err("DEVNAME unspecified
  ");
151060ac1   Tejun Heo   CUSE: implement C...
287
288
289
290
291
292
293
294
295
296
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static void cuse_gendev_release(struct device *dev)
  {
  	kfree(dev);
  }
b50ef7c52   Miklos Szeredi   cuse: convert ini...
297
298
299
300
301
302
303
  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...
304
305
306
307
308
309
310
  /**
   * 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.
   */
b50ef7c52   Miklos Szeredi   cuse: convert ini...
311
312
  static void cuse_process_init_reply(struct fuse_conn *fc,
  				    struct fuse_args *args, int error)
151060ac1   Tejun Heo   CUSE: implement C...
313
  {
b50ef7c52   Miklos Szeredi   cuse: convert ini...
314
315
  	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...
316
  	struct cuse_conn *cc = fc_to_cc(fc), *pos;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
317
318
  	struct cuse_init_out *arg = &ia->out;
  	struct page *page = ap->pages[0];
151060ac1   Tejun Heo   CUSE: implement C...
319
320
321
322
  	struct cuse_devinfo devinfo = { };
  	struct device *dev;
  	struct cdev *cdev;
  	dev_t devt;
30783587b   David Herrmann   cuse: do not regi...
323
  	int rc, i;
151060ac1   Tejun Heo   CUSE: implement C...
324

b50ef7c52   Miklos Szeredi   cuse: convert ini...
325
  	if (error || arg->major != FUSE_KERNEL_VERSION || arg->minor < 11)
151060ac1   Tejun Heo   CUSE: implement C...
326
  		goto err;
151060ac1   Tejun Heo   CUSE: implement C...
327
328
329
330
331
332
333
  
  	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...
334
  	rc = cuse_parse_devinfo(page_address(page), ap->args.out_args[1].size,
151060ac1   Tejun Heo   CUSE: implement C...
335
336
337
338
339
340
341
342
343
344
345
  				&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...
346
347
  		pr_err("failed to register chrdev region
  ");
151060ac1   Tejun Heo   CUSE: implement C...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  		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...
364
365
366
367
368
369
370
371
  	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...
372
373
  	rc = device_add(dev);
  	if (rc)
30783587b   David Herrmann   cuse: do not regi...
374
  		goto err_unlock;
151060ac1   Tejun Heo   CUSE: implement C...
375
376
377
378
379
  
  	/* register cdev */
  	rc = -ENOMEM;
  	cdev = cdev_alloc();
  	if (!cdev)
30783587b   David Herrmann   cuse: do not regi...
380
  		goto err_unlock;
151060ac1   Tejun Heo   CUSE: implement C...
381
382
383
384
385
386
387
388
389
390
391
392
  
  	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...
393
  	list_add(&cc->list, cuse_conntbl_head(devt));
8ce03fd76   David Herrmann   cuse: use mutex a...
394
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
395
396
397
398
399
  
  	/* announce device availability */
  	dev_set_uevent_suppress(dev, 0);
  	kobject_uevent(&dev->kobj, KOBJ_ADD);
  out:
b50ef7c52   Miklos Szeredi   cuse: convert ini...
400
  	kfree(ia);
151060ac1   Tejun Heo   CUSE: implement C...
401
402
403
404
405
  	__free_page(page);
  	return;
  
  err_cdev:
  	cdev_del(cdev);
30783587b   David Herrmann   cuse: do not regi...
406
407
  err_unlock:
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
408
409
410
411
  	put_device(dev);
  err_region:
  	unregister_chrdev_region(devt, 1);
  err:
eb98e3bdf   Miklos Szeredi   fuse: clean up ab...
412
  	fuse_abort_conn(fc);
151060ac1   Tejun Heo   CUSE: implement C...
413
414
415
416
417
418
  	goto out;
  }
  
  static int cuse_send_init(struct cuse_conn *cc)
  {
  	int rc;
151060ac1   Tejun Heo   CUSE: implement C...
419
420
  	struct page *page;
  	struct fuse_conn *fc = &cc->fc;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
421
422
  	struct cuse_init_args *ia;
  	struct fuse_args_pages *ap;
151060ac1   Tejun Heo   CUSE: implement C...
423
424
  
  	BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
151060ac1   Tejun Heo   CUSE: implement C...
425
426
427
  	rc = -ENOMEM;
  	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
  	if (!page)
b50ef7c52   Miklos Szeredi   cuse: convert ini...
428
  		goto err;
151060ac1   Tejun Heo   CUSE: implement C...
429

b50ef7c52   Miklos Szeredi   cuse: convert ini...
430
431
  	ia = kzalloc(sizeof(*ia), GFP_KERNEL);
  	if (!ia)
07d5f69b4   Miklos Szeredi   fuse: reduce size...
432
  		goto err_free_page;
b50ef7c52   Miklos Szeredi   cuse: convert ini...
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  	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;
  	ap->args.out_argvar = 1;
  	ap->args.out_pages = 1;
  	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;
  
  	rc = fuse_simple_background(fc, &ap->args, GFP_KERNEL);
  	if (rc) {
  		kfree(ia);
07d5f69b4   Miklos Szeredi   fuse: reduce size...
457
  err_free_page:
b50ef7c52   Miklos Szeredi   cuse: convert ini...
458
459
  		__free_page(page);
  	}
151060ac1   Tejun Heo   CUSE: implement C...
460
461
462
463
464
465
466
  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...
467
  	kfree_rcu(cc, fc.rcu);
151060ac1   Tejun Heo   CUSE: implement C...
468
469
470
471
472
473
474
475
  }
  
  /**
   * 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...
476
   * and replying to the initialization request kernel sends.  This
151060ac1   Tejun Heo   CUSE: implement C...
477
478
479
480
481
482
483
484
485
486
   * 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...
487
  	struct fuse_dev *fud;
151060ac1   Tejun Heo   CUSE: implement C...
488
489
490
491
492
493
494
  	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...
495
496
497
498
  	/*
  	 * Limit the cuse channel to requests that can
  	 * be represented in file->f_cred->user_ns.
  	 */
ae3aad77f   Stefan Hajnoczi   fuse: add fuse_iq...
499
  	fuse_conn_init(&cc->fc, file->f_cred->user_ns, &fuse_dev_fiq_ops, NULL);
151060ac1   Tejun Heo   CUSE: implement C...
500

0cd1eb9a4   Vivek Goyal   fuse: separate fu...
501
  	fud = fuse_dev_alloc_install(&cc->fc);
cc080e9e9   Miklos Szeredi   fuse: introduce p...
502
503
504
505
  	if (!fud) {
  		kfree(cc);
  		return -ENOMEM;
  	}
151060ac1   Tejun Heo   CUSE: implement C...
506
507
  	INIT_LIST_HEAD(&cc->list);
  	cc->fc.release = cuse_fc_release;
796523fb2   Maxim Patlasov   fuse: add flag fc...
508
  	cc->fc.initialized = 1;
151060ac1   Tejun Heo   CUSE: implement C...
509
510
  	rc = cuse_send_init(cc);
  	if (rc) {
cc080e9e9   Miklos Szeredi   fuse: introduce p...
511
  		fuse_dev_free(fud);
9ad09b197   zhengbin   fuse: fix memleak...
512
  		fuse_conn_put(&cc->fc);
151060ac1   Tejun Heo   CUSE: implement C...
513
514
  		return rc;
  	}
cc080e9e9   Miklos Szeredi   fuse: introduce p...
515
  	file->private_data = fud;
151060ac1   Tejun Heo   CUSE: implement C...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  
  	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...
533
534
  	struct fuse_dev *fud = file->private_data;
  	struct cuse_conn *cc = fc_to_cc(fud->fc);
151060ac1   Tejun Heo   CUSE: implement C...
535
536
537
  	int rc;
  
  	/* remove from the conntbl, no more access from this point on */
8ce03fd76   David Herrmann   cuse: use mutex a...
538
  	mutex_lock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
539
  	list_del_init(&cc->list);
8ce03fd76   David Herrmann   cuse: use mutex a...
540
  	mutex_unlock(&cuse_lock);
151060ac1   Tejun Heo   CUSE: implement C...
541
542
543
544
545
546
547
548
  
  	/* 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 ...
549
550
  	/* Base reference is now owned by "fud" */
  	fuse_conn_put(&cc->fc);
151060ac1   Tejun Heo   CUSE: implement C...
551

151060ac1   Tejun Heo   CUSE: implement C...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  	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...
574
  static DEVICE_ATTR(waiting, 0400, cuse_class_waiting_show, NULL);
151060ac1   Tejun Heo   CUSE: implement C...
575
576
577
578
579
580
  
  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...
581
  	fuse_abort_conn(&cc->fc);
151060ac1   Tejun Heo   CUSE: implement C...
582
583
  	return count;
  }
58f86cc89   Rusty Russell   VERIFY_OCTAL_PERM...
584
  static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
151060ac1   Tejun Heo   CUSE: implement C...
585

4183fb950   Greg Kroah-Hartman   cuse: convert cla...
586
587
588
589
  static struct attribute *cuse_class_dev_attrs[] = {
  	&dev_attr_waiting.attr,
  	&dev_attr_abort.attr,
  	NULL,
151060ac1   Tejun Heo   CUSE: implement C...
590
  };
4183fb950   Greg Kroah-Hartman   cuse: convert cla...
591
  ATTRIBUTE_GROUPS(cuse_class_dev);
151060ac1   Tejun Heo   CUSE: implement C...
592
593
  
  static struct miscdevice cuse_miscdev = {
cb2ffb26e   Tom Gundersen   cuse: add fix min...
594
  	.minor		= CUSE_MINOR,
151060ac1   Tejun Heo   CUSE: implement C...
595
596
597
  	.name		= "cuse",
  	.fops		= &cuse_channel_fops,
  };
cb2ffb26e   Tom Gundersen   cuse: add fix min...
598
599
  MODULE_ALIAS_MISCDEV(CUSE_MINOR);
  MODULE_ALIAS("devname:cuse");
151060ac1   Tejun Heo   CUSE: implement C...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  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...
617
  	cuse_class->dev_groups = cuse_class_dev_groups;
151060ac1   Tejun Heo   CUSE: implement C...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  
  	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");