Blame view

fs/coda/psdev.c 10.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   *      	An implementation of a loadable kernel mode driver providing
   *		multiple kernel/user space bidirectional communications links.
   *
526719ba5   Alan Cox   Switch to a valid...
5
   * 		Author: 	Alan Cox <alan@lxorguk.ukuu.org.uk>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   * 
   *              Adapted to become the Linux 2.0 Coda pseudo device
   *              Peter  Braam  <braam@maths.ox.ac.uk> 
   *              Michael Callahan <mjc@emmy.smith.edu>           
   *
   *              Changes for Linux 2.1
   *              Copyright (c) 1997 Carnegie-Mellon University
   */
  
  #include <linux/module.h>
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/major.h>
  #include <linux/time.h>
a99bbaf5e   Alexey Dobriyan   headers: remove s...
25
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
  #include <linux/slab.h>
  #include <linux/ioport.h>
  #include <linux/fcntl.h>
  #include <linux/delay.h>
  #include <linux/skbuff.h>
  #include <linux/proc_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
  #include <linux/vmalloc.h>
  #include <linux/fs.h>
  #include <linux/file.h>
  #include <linux/poll.h>
  #include <linux/init.h>
  #include <linux/list.h>
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
38
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
45
  #include <linux/device.h>
  #include <asm/io.h>
  #include <asm/system.h>
  #include <asm/poll.h>
  #include <asm/uaccess.h>
  
  #include <linux/coda.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #include <linux/coda_psdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

31a203df9   Al Viro   take coda-private...
48
  #include "coda_linux.h"
c98d8cfbc   Adrian Bunk   [PATCH] fs/coda/:...
49
  #include "coda_int.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
  /* statistics */
  int           coda_hard;         /* allows signals during upcalls */
  unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
  
  
  struct venus_comm coda_comms[MAX_CODADEVS];
1db560afe   Greg Kroah-Hartman   [PATCH] class: co...
57
  static struct class *coda_psdev_class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
68
  
  /*
   * Device operations
   */
  
  static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
  {
          struct venus_comm *vcp = (struct venus_comm *) file->private_data;
  	unsigned int mask = POLLOUT | POLLWRNORM;
  
  	poll_wait(file, &vcp->vc_waitq, wait);
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
69
  	mutex_lock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  	if (!list_empty(&vcp->vc_pending))
                  mask |= POLLIN | POLLRDNORM;
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
72
  	mutex_unlock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
  
  	return mask;
  }
977183902   Arnd Bergmann   coda/psdev: Remov...
76
  static long coda_psdev_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  {
  	unsigned int data;
  
  	switch(cmd) {
  	case CIOC_KERNEL_VERSION:
  		data = CODA_KERNEL_VERSION;
  		return put_user(data, (int __user *) arg);
  	default:
  		return -ENOTTY;
  	}
  
  	return 0;
  }
  
  /*
   *	Receive a message written by Venus to the psdev
   */
   
  static ssize_t coda_psdev_write(struct file *file, const char __user *buf, 
  				size_t nbytes, loff_t *off)
  {
          struct venus_comm *vcp = (struct venus_comm *) file->private_data;
          struct upc_req *req = NULL;
          struct upc_req *tmp;
  	struct list_head *lh;
  	struct coda_in_hdr hdr;
  	ssize_t retval = 0, count = 0;
  	int error;
  
          /* Peek at the opcode, uniquefier */
  	if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
  	        return -EFAULT;
  
          if (DOWNCALL(hdr.opcode)) {
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
111
  		union outputArgs *dcbuf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  		int size = sizeof(*dcbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  		if  ( nbytes < sizeof(struct coda_out_hdr) ) {
  		        printk("coda_downcall opc %d uniq %d, not enough!
  ",
  			       hdr.opcode, hdr.unique);
  			count = nbytes;
  			goto out;
  		}
  		if ( nbytes > size ) {
  		        printk("Coda: downcall opc %d, uniq %d, too much!",
  			       hdr.opcode, hdr.unique);
  		        nbytes = size;
  		}
  		CODA_ALLOC(dcbuf, union outputArgs *, nbytes);
  		if (copy_from_user(dcbuf, buf, nbytes)) {
  			CODA_FREE(dcbuf, nbytes);
  			retval = -EFAULT;
  			goto out;
  		}
  
  		/* what downcall errors does Venus handle ? */
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
133
  		error = coda_downcall(vcp, hdr.opcode, dcbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
140
141
142
143
144
145
146
  
  		CODA_FREE(dcbuf, nbytes);
  		if (error) {
  		        printk("psdev_write: coda_downcall error: %d
  ", error);
  			retval = error;
  			goto out;
  		}
  		count = nbytes;
  		goto out;
  	}
          
  	/* Look for the message on the processing queue. */
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
147
  	mutex_lock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
153
154
155
  	list_for_each(lh, &vcp->vc_processing) {
  		tmp = list_entry(lh, struct upc_req , uc_chain);
  		if (tmp->uc_unique == hdr.unique) {
  			req = tmp;
  			list_del(&req->uc_chain);
  			break;
  		}
  	}
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
156
  	mutex_unlock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  
  	if (!req) {
  		printk("psdev_write: msg (%d, %d) not found
  ", 
  			hdr.opcode, hdr.unique);
  		retval = -ESRCH;
  		goto out;
  	}
  
          /* move data into response buffer. */
  	if (req->uc_outSize < nbytes) {
                  printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %d, uniq: %d.
  ",
  		       req->uc_outSize, (long)nbytes, hdr.opcode, hdr.unique);
  		nbytes = req->uc_outSize; /* don't have more space! */
  	}
          if (copy_from_user(req->uc_data, buf, nbytes)) {
4aeefdc69   Jens Axboe   coda: fixup clash...
174
  		req->uc_flags |= CODA_REQ_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
  		wake_up(&req->uc_sleep);
  		retval = -EFAULT;
  		goto out;
  	}
  
  	/* adjust outsize. is this useful ?? */
112d421df   Jan Harkes   Coda: mount hangs...
181
182
  	req->uc_outSize = nbytes;
  	req->uc_flags |= CODA_REQ_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
188
  	count = nbytes;
  
  	/* Convert filedescriptor into a file handle */
  	if (req->uc_opcode == CODA_OPEN_BY_FD) {
  		struct coda_open_by_fd_out *outp =
  			(struct coda_open_by_fd_out *)req->uc_data;
38c2e4370   Jan Harkes   coda: do not grab...
189
190
  		if (!outp->oh.result)
  			outp->fh = fget(outp->fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  	}
  
          wake_up(&req->uc_sleep);
  out:
          return(count ? count : retval);  
  }
  
  /*
   *	Read a message from the kernel to Venus
   */
  
  static ssize_t coda_psdev_read(struct file * file, char __user * buf, 
  			       size_t nbytes, loff_t *off)
  {
  	DECLARE_WAITQUEUE(wait, current);
          struct venus_comm *vcp = (struct venus_comm *) file->private_data;
          struct upc_req *req;
  	ssize_t retval = 0, count = 0;
  
  	if (nbytes == 0)
  		return 0;
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
212
  	mutex_lock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
220
221
222
223
224
225
  
  	add_wait_queue(&vcp->vc_waitq, &wait);
  	set_current_state(TASK_INTERRUPTIBLE);
  
  	while (list_empty(&vcp->vc_pending)) {
  		if (file->f_flags & O_NONBLOCK) {
  			retval = -EAGAIN;
  			break;
  		}
  		if (signal_pending(current)) {
  			retval = -ERESTARTSYS;
  			break;
  		}
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
226
  		mutex_unlock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  		schedule();
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
228
  		mutex_lock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  	}
  
  	set_current_state(TASK_RUNNING);
  	remove_wait_queue(&vcp->vc_waitq, &wait);
  
  	if (retval)
  		goto out;
  
  	req = list_entry(vcp->vc_pending.next, struct upc_req,uc_chain);
  	list_del(&req->uc_chain);
  
  	/* Move the input args into userspace */
  	count = req->uc_inSize;
  	if (nbytes < req->uc_inSize) {
                  printk ("psdev_read: Venus read %ld bytes of %d in message
  ",
  			(long)nbytes, req->uc_inSize);
  		count = nbytes;
          }
  
  	if (copy_to_user(buf, req->uc_data, count))
  	        retval = -EFAULT;
          
  	/* If request was not a signal, enqueue and don't free */
4aeefdc69   Jens Axboe   coda: fixup clash...
253
254
  	if (!(req->uc_flags & CODA_REQ_ASYNC)) {
  		req->uc_flags |= CODA_REQ_READ;
8e13059a3   Akinobu Mita   [PATCH] use list_...
255
  		list_add_tail(&(req->uc_chain), &vcp->vc_processing);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
  		goto out;
  	}
  
  	CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
37461e195   Jan Harkes   coda: replace upc...
260
  	kfree(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  out:
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
262
  	mutex_unlock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
  	return (count ? count : retval);
  }
  
  static int coda_psdev_open(struct inode * inode, struct file * file)
  {
870655196   Jan Harkes   coda: cleanup /de...
268
269
  	struct venus_comm *vcp;
  	int idx, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	idx = iminor(inode);
870655196   Jan Harkes   coda: cleanup /de...
272
  	if (idx < 0 || idx >= MAX_CODADEVS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274

870655196   Jan Harkes   coda: cleanup /de...
275
  	err = -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	vcp = &coda_comms[idx];
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
277
  	mutex_lock(&vcp->vc_mutex);
870655196   Jan Harkes   coda: cleanup /de...
278
279
  	if (!vcp->vc_inuse) {
  		vcp->vc_inuse++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
  		INIT_LIST_HEAD(&vcp->vc_pending);
  		INIT_LIST_HEAD(&vcp->vc_processing);
  		init_waitqueue_head(&vcp->vc_waitq);
  		vcp->vc_sb = NULL;
  		vcp->vc_seq = 0;
870655196   Jan Harkes   coda: cleanup /de...
285
286
287
  
  		file->private_data = vcp;
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289

da47c19e5   Yoshihisa Abe   Coda: replace BKL...
290
  	mutex_unlock(&vcp->vc_mutex);
870655196   Jan Harkes   coda: cleanup /de...
291
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
  }
  
  
  static int coda_psdev_release(struct inode * inode, struct file * file)
  {
870655196   Jan Harkes   coda: cleanup /de...
297
298
  	struct venus_comm *vcp = (struct venus_comm *) file->private_data;
  	struct upc_req *req, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299

870655196   Jan Harkes   coda: cleanup /de...
300
  	if (!vcp || !vcp->vc_inuse ) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
  		printk("psdev_release: Not open.
  ");
  		return -1;
  	}
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
305
  	mutex_lock(&vcp->vc_mutex);
870655196   Jan Harkes   coda: cleanup /de...
306
307
  
  	/* Wakeup clients so they can return. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
870655196   Jan Harkes   coda: cleanup /de...
309
  		list_del(&req->uc_chain);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  		/* Async requests need to be freed here */
4aeefdc69   Jens Axboe   coda: fixup clash...
311
  		if (req->uc_flags & CODA_REQ_ASYNC) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  			CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
37461e195   Jan Harkes   coda: replace upc...
313
  			kfree(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
  			continue;
  		}
4aeefdc69   Jens Axboe   coda: fixup clash...
316
  		req->uc_flags |= CODA_REQ_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  		wake_up(&req->uc_sleep);
870655196   Jan Harkes   coda: cleanup /de...
318
319
320
321
  	}
  
  	list_for_each_entry_safe(req, tmp, &vcp->vc_processing, uc_chain) {
  		list_del(&req->uc_chain);
4aeefdc69   Jens Axboe   coda: fixup clash...
322
  		req->uc_flags |= CODA_REQ_ABORT;
870655196   Jan Harkes   coda: cleanup /de...
323
324
  		wake_up(&req->uc_sleep);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325

870655196   Jan Harkes   coda: cleanup /de...
326
327
  	file->private_data = NULL;
  	vcp->vc_inuse--;
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
328
  	mutex_unlock(&vcp->vc_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
  	return 0;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
331
  static const struct file_operations coda_psdev_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
  	.owner		= THIS_MODULE,
  	.read		= coda_psdev_read,
  	.write		= coda_psdev_write,
  	.poll		= coda_psdev_poll,
977183902   Arnd Bergmann   coda/psdev: Remov...
336
  	.unlocked_ioctl	= coda_psdev_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
  	.open		= coda_psdev_open,
  	.release	= coda_psdev_release,
6038f373a   Arnd Bergmann   llseek: automatic...
339
  	.llseek		= noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
348
349
350
  };
  
  static int init_coda_psdev(void)
  {
  	int i, err = 0;
  	if (register_chrdev(CODA_PSDEV_MAJOR, "coda", &coda_psdev_fops)) {
                printk(KERN_ERR "coda_psdev: unable to get major %d
  ", 
  		     CODA_PSDEV_MAJOR);
                return -EIO;
  	}
1db560afe   Greg Kroah-Hartman   [PATCH] class: co...
351
  	coda_psdev_class = class_create(THIS_MODULE, "coda");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
  	if (IS_ERR(coda_psdev_class)) {
  		err = PTR_ERR(coda_psdev_class);
  		goto out_chrdev;
  	}		
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
356
357
  	for (i = 0; i < MAX_CODADEVS; i++) {
  		mutex_init(&(&coda_comms[i])->vc_mutex);
a9b12619f   Greg Kroah-Hartman   device create: mi...
358
359
  		device_create(coda_psdev_class, NULL,
  			      MKDEV(CODA_PSDEV_MAJOR, i), NULL, "cfs%d", i);
da47c19e5   Yoshihisa Abe   Coda: replace BKL...
360
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
  	coda_sysctl_init();
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
  out_chrdev:
  	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
  out:
  	return err;
  }
5b7f13bd2   Jan Harkes   coda: update modu...
368
369
370
  MODULE_AUTHOR("Jan Harkes, Peter J. Braam");
  MODULE_DESCRIPTION("Coda Distributed File System VFS interface");
  MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  MODULE_LICENSE("GPL");
5b7f13bd2   Jan Harkes   coda: update modu...
372
  MODULE_VERSION("6.6");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
  static int __init init_coda(void)
  {
  	int status;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  
  	status = coda_init_inodecache();
  	if (status)
  		goto out2;
  	status = init_coda_psdev();
  	if ( status ) {
  		printk("Problem (%d) in init_coda_psdev
  ", status);
  		goto out1;
  	}
  	
  	status = register_filesystem(&coda_fs_type);
  	if (status) {
  		printk("coda: failed to register filesystem!
  ");
  		goto out;
  	}
  	return 0;
  out:
8ab5e4c15   Greg Kroah-Hartman   [PATCH] devfs: Re...
397
  	for (i = 0; i < MAX_CODADEVS; i++)
62ca87925   Kay Sievers   coda: convert str...
398
  		device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
1db560afe   Greg Kroah-Hartman   [PATCH] class: co...
399
  	class_destroy(coda_psdev_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
  	coda_sysctl_clean();
  out1:
  	coda_destroy_inodecache();
  out2:
  	return status;
  }
  
  static void __exit exit_coda(void)
  {
          int err, i;
  
  	err = unregister_filesystem(&coda_fs_type);
          if ( err != 0 ) {
                  printk("coda: failed to unregister filesystem
  ");
          }
8ab5e4c15   Greg Kroah-Hartman   [PATCH] devfs: Re...
417
  	for (i = 0; i < MAX_CODADEVS; i++)
62ca87925   Kay Sievers   coda: convert str...
418
  		device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i));
1db560afe   Greg Kroah-Hartman   [PATCH] class: co...
419
  	class_destroy(coda_psdev_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
426
  	unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
  	coda_sysctl_clean();
  	coda_destroy_inodecache();
  }
  
  module_init(init_coda);
  module_exit(exit_coda);