source: src/linux/universal/linux-4.9/fs/orangefs/devorangefs-req.c @ 31884

Last change on this file since 31884 was 31884, checked in by brainslayer, 6 weeks ago

update kernels

File size: 22.5 KB
Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * Changes by Acxiom Corporation to add protocol version to kernel
5 * communication, Copyright Acxiom Corporation, 2005.
6 *
7 * See COPYING in top-level directory.
8 */
9
10#include "protocol.h"
11#include "orangefs-kernel.h"
12#include "orangefs-dev-proto.h"
13#include "orangefs-bufmap.h"
14#include "orangefs-debugfs.h"
15
16#include <linux/debugfs.h>
17#include <linux/slab.h>
18
19/* this file implements the /dev/pvfs2-req device node */
20
21uint32_t orangefs_userspace_version;
22
23static int open_access_count;
24
25static DEFINE_MUTEX(devreq_mutex);
26
27#define DUMP_DEVICE_ERROR()                                                   \
28do {                                                                          \
29        gossip_err("*****************************************************\n");\
30        gossip_err("ORANGEFS Device Error:  You cannot open the device file ");  \
31        gossip_err("\n/dev/%s more than once.  Please make sure that\nthere " \
32                   "are no ", ORANGEFS_REQDEVICE_NAME);                          \
33        gossip_err("instances of a program using this device\ncurrently "     \
34                   "running. (You must verify this!)\n");                     \
35        gossip_err("For example, you can use the lsof program as follows:\n");\
36        gossip_err("'lsof | grep %s' (run this as root)\n",                   \
37                   ORANGEFS_REQDEVICE_NAME);                                     \
38        gossip_err("  open_access_count = %d\n", open_access_count);          \
39        gossip_err("*****************************************************\n");\
40} while (0)
41
42static int hash_func(__u64 tag, int table_size)
43{
44        return do_div(tag, (unsigned int)table_size);
45}
46
47static void orangefs_devreq_add_op(struct orangefs_kernel_op_s *op)
48{
49        int index = hash_func(op->tag, hash_table_size);
50
51        list_add_tail(&op->list, &orangefs_htable_ops_in_progress[index]);
52}
53
54/*
55 * find the op with this tag and remove it from the in progress
56 * hash table.
57 */
58static struct orangefs_kernel_op_s *orangefs_devreq_remove_op(__u64 tag)
59{
60        struct orangefs_kernel_op_s *op, *next;
61        int index;
62
63        index = hash_func(tag, hash_table_size);
64
65        spin_lock(&orangefs_htable_ops_in_progress_lock);
66        list_for_each_entry_safe(op,
67                                 next,
68                                 &orangefs_htable_ops_in_progress[index],
69                                 list) {
70                if (op->tag == tag && !op_state_purged(op) &&
71                    !op_state_given_up(op)) {
72                        list_del_init(&op->list);
73                        spin_unlock(&orangefs_htable_ops_in_progress_lock);
74                        return op;
75                }
76        }
77
78        spin_unlock(&orangefs_htable_ops_in_progress_lock);
79        return NULL;
80}
81
82/* Returns whether any FS are still pending remounted */
83static int mark_all_pending_mounts(void)
84{
85        int unmounted = 1;
86        struct orangefs_sb_info_s *orangefs_sb = NULL;
87
88        spin_lock(&orangefs_superblocks_lock);
89        list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
90                /* All of these file system require a remount */
91                orangefs_sb->mount_pending = 1;
92                unmounted = 0;
93        }
94        spin_unlock(&orangefs_superblocks_lock);
95        return unmounted;
96}
97
98/*
99 * Determine if a given file system needs to be remounted or not
100 *  Returns -1 on error
101 *           0 if already mounted
102 *           1 if needs remount
103 */
104static int fs_mount_pending(__s32 fsid)
105{
106        int mount_pending = -1;
107        struct orangefs_sb_info_s *orangefs_sb = NULL;
108
109        spin_lock(&orangefs_superblocks_lock);
110        list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
111                if (orangefs_sb->fs_id == fsid) {
112                        mount_pending = orangefs_sb->mount_pending;
113                        break;
114                }
115        }
116        spin_unlock(&orangefs_superblocks_lock);
117        return mount_pending;
118}
119
120static int orangefs_devreq_open(struct inode *inode, struct file *file)
121{
122        int ret = -EINVAL;
123
124        /* in order to ensure that the filesystem driver sees correct UIDs */
125        if (file->f_cred->user_ns != &init_user_ns) {
126                gossip_err("%s: device cannot be opened outside init_user_ns\n",
127                           __func__);
128                goto out;
129        }
130
131        if (!(file->f_flags & O_NONBLOCK)) {
132                gossip_err("%s: device cannot be opened in blocking mode\n",
133                           __func__);
134                goto out;
135        }
136        ret = -EACCES;
137        gossip_debug(GOSSIP_DEV_DEBUG, "client-core: opening device\n");
138        mutex_lock(&devreq_mutex);
139
140        if (open_access_count == 0) {
141                open_access_count = 1;
142                ret = 0;
143        } else {
144                DUMP_DEVICE_ERROR();
145        }
146        mutex_unlock(&devreq_mutex);
147
148out:
149
150        gossip_debug(GOSSIP_DEV_DEBUG,
151                     "pvfs2-client-core: open device complete (ret = %d)\n",
152                     ret);
153        return ret;
154}
155
156/* Function for read() callers into the device */
157static ssize_t orangefs_devreq_read(struct file *file,
158                                 char __user *buf,
159                                 size_t count, loff_t *offset)
160{
161        struct orangefs_kernel_op_s *op, *temp;
162        __s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION;
163        static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
164        struct orangefs_kernel_op_s *cur_op = NULL;
165        unsigned long ret;
166
167        /* We do not support blocking IO. */
168        if (!(file->f_flags & O_NONBLOCK)) {
169                gossip_err("%s: blocking read from client-core.\n",
170                           __func__);
171                return -EINVAL;
172        }
173
174        /*
175         * The client will do an ioctl to find MAX_DEV_REQ_UPSIZE, then
176         * always read with that size buffer.
177         */
178        if (count != MAX_DEV_REQ_UPSIZE) {
179                gossip_err("orangefs: client-core tried to read wrong size\n");
180                return -EINVAL;
181        }
182
183restart:
184        /* Get next op (if any) from top of list. */
185        spin_lock(&orangefs_request_list_lock);
186        list_for_each_entry_safe(op, temp, &orangefs_request_list, list) {
187                __s32 fsid;
188                /* This lock is held past the end of the loop when we break. */
189                spin_lock(&op->lock);
190                if (unlikely(op_state_purged(op) || op_state_given_up(op))) {
191                        spin_unlock(&op->lock);
192                        continue;
193                }
194
195                fsid = fsid_of_op(op);
196                if (fsid != ORANGEFS_FS_ID_NULL) {
197                        int ret;
198                        /* Skip ops whose filesystem needs to be mounted. */
199                        ret = fs_mount_pending(fsid);
200                        if (ret == 1) {
201                                gossip_debug(GOSSIP_DEV_DEBUG,
202                                    "%s: mount pending, skipping op tag "
203                                    "%llu %s\n",
204                                    __func__,
205                                    llu(op->tag),
206                                    get_opname_string(op));
207                                spin_unlock(&op->lock);
208                                continue;
209                        /*
210                         * Skip ops whose filesystem we don't know about unless
211                         * it is being mounted.
212                         */
213                        /* XXX: is there a better way to detect this? */
214                        } else if (ret == -1 &&
215                                   !(op->upcall.type ==
216                                        ORANGEFS_VFS_OP_FS_MOUNT ||
217                                     op->upcall.type ==
218                                        ORANGEFS_VFS_OP_GETATTR)) {
219                                gossip_debug(GOSSIP_DEV_DEBUG,
220                                    "orangefs: skipping op tag %llu %s\n",
221                                    llu(op->tag), get_opname_string(op));
222                                gossip_err(
223                                    "orangefs: ERROR: fs_mount_pending %d\n",
224                                    fsid);
225                                spin_unlock(&op->lock);
226                                continue;
227                        }
228                }
229                /*
230                 * Either this op does not pertain to a filesystem, is mounting
231                 * a filesystem, or pertains to a mounted filesystem. Let it
232                 * through.
233                 */
234                cur_op = op;
235                break;
236        }
237
238        /*
239         * At this point we either have a valid op and can continue or have not
240         * found an op and must ask the client to try again later.
241         */
242        if (!cur_op) {
243                spin_unlock(&orangefs_request_list_lock);
244                return -EAGAIN;
245        }
246
247        gossip_debug(GOSSIP_DEV_DEBUG, "%s: reading op tag %llu %s\n",
248                     __func__,
249                     llu(cur_op->tag),
250                     get_opname_string(cur_op));
251
252        /*
253         * Such an op should never be on the list in the first place. If so, we
254         * will abort.
255         */
256        if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) {
257                gossip_err("orangefs: ERROR: Current op already queued.\n");
258                list_del_init(&cur_op->list);
259                spin_unlock(&cur_op->lock);
260                spin_unlock(&orangefs_request_list_lock);
261                return -EAGAIN;
262        }
263
264        list_del_init(&cur_op->list);
265        spin_unlock(&orangefs_request_list_lock);
266
267        spin_unlock(&cur_op->lock);
268
269        /* Push the upcall out. */
270        ret = copy_to_user(buf, &proto_ver, sizeof(__s32));
271        if (ret != 0)
272                goto error;
273        ret = copy_to_user(buf+sizeof(__s32), &magic, sizeof(__s32));
274        if (ret != 0)
275                goto error;
276        ret = copy_to_user(buf+2 * sizeof(__s32), &cur_op->tag, sizeof(__u64));
277        if (ret != 0)
278                goto error;
279        ret = copy_to_user(buf+2*sizeof(__s32)+sizeof(__u64), &cur_op->upcall,
280                           sizeof(struct orangefs_upcall_s));
281        if (ret != 0)
282                goto error;
283
284        spin_lock(&orangefs_htable_ops_in_progress_lock);
285        spin_lock(&cur_op->lock);
286        if (unlikely(op_state_given_up(cur_op))) {
287                spin_unlock(&cur_op->lock);
288                spin_unlock(&orangefs_htable_ops_in_progress_lock);
289                complete(&cur_op->waitq);
290                goto restart;
291        }
292
293        /*
294         * Set the operation to be in progress and move it between lists since
295         * it has been sent to the client.
296         */
297        set_op_state_inprogress(cur_op);
298        gossip_debug(GOSSIP_DEV_DEBUG,
299                     "%s: 1 op:%s: op_state:%d: process:%s:\n",
300                     __func__,
301                     get_opname_string(cur_op),
302                     cur_op->op_state,
303                     current->comm);
304        orangefs_devreq_add_op(cur_op);
305        spin_unlock(&cur_op->lock);
306        spin_unlock(&orangefs_htable_ops_in_progress_lock);
307
308        /* The client only asks to read one size buffer. */
309        return MAX_DEV_REQ_UPSIZE;
310error:
311        /*
312         * We were unable to copy the op data to the client. Put the op back in
313         * list. If client has crashed, the op will be purged later when the
314         * device is released.
315         */
316        gossip_err("orangefs: Failed to copy data to user space\n");
317        spin_lock(&orangefs_request_list_lock);
318        spin_lock(&cur_op->lock);
319        if (likely(!op_state_given_up(cur_op))) {
320                set_op_state_waiting(cur_op);
321                gossip_debug(GOSSIP_DEV_DEBUG,
322                             "%s: 2 op:%s: op_state:%d: process:%s:\n",
323                             __func__,
324                             get_opname_string(cur_op),
325                             cur_op->op_state,
326                             current->comm);
327                list_add(&cur_op->list, &orangefs_request_list);
328                spin_unlock(&cur_op->lock);
329        } else {
330                spin_unlock(&cur_op->lock);
331                complete(&cur_op->waitq);
332        }
333        spin_unlock(&orangefs_request_list_lock);
334        return -EFAULT;
335}
336
337/*
338 * Function for writev() callers into the device.
339 *
340 * Userspace should have written:
341 *  - __u32 version
342 *  - __u32 magic
343 *  - __u64 tag
344 *  - struct orangefs_downcall_s
345 *  - trailer buffer (in the case of READDIR operations)
346 */
347static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
348                                      struct iov_iter *iter)
349{
350        ssize_t ret;
351        struct orangefs_kernel_op_s *op = NULL;
352        struct {
353                __u32 version;
354                __u32 magic;
355                __u64 tag;
356        } head;
357        int total = ret = iov_iter_count(iter);
358        int n;
359        int downcall_size = sizeof(struct orangefs_downcall_s);
360        int head_size = sizeof(head);
361
362        gossip_debug(GOSSIP_DEV_DEBUG, "%s: total:%d: ret:%zd:\n",
363                     __func__,
364                     total,
365                     ret);
366
367        if (total < MAX_DEV_REQ_DOWNSIZE) {
368                gossip_err("%s: total:%d: must be at least:%u:\n",
369                           __func__,
370                           total,
371                           (unsigned int) MAX_DEV_REQ_DOWNSIZE);
372                return -EFAULT;
373        }
374     
375        n = copy_from_iter(&head, head_size, iter);
376        if (n < head_size) {
377                gossip_err("%s: failed to copy head.\n", __func__);
378                return -EFAULT;
379        }
380
381        if (head.version < ORANGEFS_MINIMUM_USERSPACE_VERSION) {
382                gossip_err("%s: userspace claims version"
383                           "%d, minimum version required: %d.\n",
384                           __func__,
385                           head.version,
386                           ORANGEFS_MINIMUM_USERSPACE_VERSION);
387                return -EPROTO;
388        }
389
390        if (head.magic != ORANGEFS_DEVREQ_MAGIC) {
391                gossip_err("Error: Device magic number does not match.\n");
392                return -EPROTO;
393        }
394
395        if (!orangefs_userspace_version) {
396                orangefs_userspace_version = head.version;
397        } else if (orangefs_userspace_version != head.version) {
398                gossip_err("Error: userspace version changes\n");
399                return -EPROTO;
400        }
401
402        /* remove the op from the in progress hash table */
403        op = orangefs_devreq_remove_op(head.tag);
404        if (!op) {
405                gossip_debug(GOSSIP_DEV_DEBUG,
406                             "%s: No one's waiting for tag %llu\n",
407                             __func__, llu(head.tag));
408                return ret;
409        }
410
411        n = copy_from_iter(&op->downcall, downcall_size, iter);
412        if (n != downcall_size) {
413                gossip_err("%s: failed to copy downcall.\n", __func__);
414                goto Efault;
415        }
416
417        if (op->downcall.status)
418                goto wakeup;
419
420        /*
421         * We've successfully peeled off the head and the downcall.
422         * Something has gone awry if total doesn't equal the
423         * sum of head_size, downcall_size and trailer_size.
424         */
425        if ((head_size + downcall_size + op->downcall.trailer_size) != total) {
426                gossip_err("%s: funky write, head_size:%d"
427                           ": downcall_size:%d: trailer_size:%lld"
428                           ": total size:%d:\n",
429                           __func__,
430                           head_size,
431                           downcall_size,
432                           op->downcall.trailer_size,
433                           total);
434                goto Efault;
435        }
436
437        /* Only READDIR operations should have trailers. */
438        if ((op->downcall.type != ORANGEFS_VFS_OP_READDIR) &&
439            (op->downcall.trailer_size != 0)) {
440                gossip_err("%s: %x operation with trailer.",
441                           __func__,
442                           op->downcall.type);
443                goto Efault;
444        }
445
446        /* READDIR operations should always have trailers. */
447        if ((op->downcall.type == ORANGEFS_VFS_OP_READDIR) &&
448            (op->downcall.trailer_size == 0)) {
449                gossip_err("%s: %x operation with no trailer.",
450                           __func__,
451                           op->downcall.type);
452                goto Efault;
453        }
454
455        if (op->downcall.type != ORANGEFS_VFS_OP_READDIR)
456                goto wakeup;
457
458        op->downcall.trailer_buf =
459                vmalloc(op->downcall.trailer_size);
460        if (op->downcall.trailer_buf == NULL) {
461                gossip_err("%s: failed trailer vmalloc.\n",
462                           __func__);
463                goto Enomem;
464        }
465        memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size);
466        n = copy_from_iter(op->downcall.trailer_buf,
467                           op->downcall.trailer_size,
468                           iter);
469        if (n != op->downcall.trailer_size) {
470                gossip_err("%s: failed to copy trailer.\n", __func__);
471                vfree(op->downcall.trailer_buf);
472                goto Efault;
473        }
474
475wakeup:
476        /*
477         * Return to vfs waitqueue, and back to service_operation
478         * through wait_for_matching_downcall.
479         */
480        spin_lock(&op->lock);
481        if (unlikely(op_is_cancel(op))) {
482                spin_unlock(&op->lock);
483                put_cancel(op);
484        } else if (unlikely(op_state_given_up(op))) {
485                spin_unlock(&op->lock);
486                complete(&op->waitq);
487        } else {
488                set_op_state_serviced(op);
489                gossip_debug(GOSSIP_DEV_DEBUG,
490                             "%s: op:%s: op_state:%d: process:%s:\n",
491                             __func__,
492                             get_opname_string(op),
493                             op->op_state,
494                             current->comm);
495                spin_unlock(&op->lock);
496        }
497        return ret;
498
499Efault:
500        op->downcall.status = -(ORANGEFS_ERROR_BIT | 9);
501        ret = -EFAULT;
502        goto wakeup;
503
504Enomem:
505        op->downcall.status = -(ORANGEFS_ERROR_BIT | 8);
506        ret = -ENOMEM;
507        goto wakeup;
508}
509
510/*
511 * NOTE: gets called when the last reference to this device is dropped.
512 * Using the open_access_count variable, we enforce a reference count
513 * on this file so that it can be opened by only one process at a time.
514 * the devreq_mutex is used to make sure all i/o has completed
515 * before we call orangefs_bufmap_finalize, and similar such tricky
516 * situations
517 */
518static int orangefs_devreq_release(struct inode *inode, struct file *file)
519{
520        int unmounted = 0;
521
522        gossip_debug(GOSSIP_DEV_DEBUG,
523                     "%s:pvfs2-client-core: exiting, closing device\n",
524                     __func__);
525
526        mutex_lock(&devreq_mutex);
527        orangefs_bufmap_finalize();
528
529        open_access_count = -1;
530
531        unmounted = mark_all_pending_mounts();
532        gossip_debug(GOSSIP_DEV_DEBUG, "ORANGEFS Device Close: Filesystem(s) %s\n",
533                     (unmounted ? "UNMOUNTED" : "MOUNTED"));
534
535        purge_waiting_ops();
536        purge_inprogress_ops();
537
538        orangefs_bufmap_run_down();
539
540        gossip_debug(GOSSIP_DEV_DEBUG,
541                     "pvfs2-client-core: device close complete\n");
542        open_access_count = 0;
543        orangefs_userspace_version = 0;
544        mutex_unlock(&devreq_mutex);
545        return 0;
546}
547
548int is_daemon_in_service(void)
549{
550        int in_service;
551
552        /*
553         * What this function does is checks if client-core is alive
554         * based on the access count we maintain on the device.
555         */
556        mutex_lock(&devreq_mutex);
557        in_service = open_access_count == 1 ? 0 : -EIO;
558        mutex_unlock(&devreq_mutex);
559        return in_service;
560}
561
562bool __is_daemon_in_service(void)
563{
564        return open_access_count == 1;
565}
566
567static inline long check_ioctl_command(unsigned int command)
568{
569        /* Check for valid ioctl codes */
570        if (_IOC_TYPE(command) != ORANGEFS_DEV_MAGIC) {
571                gossip_err("device ioctl magic numbers don't match! Did you rebuild pvfs2-client-core/libpvfs2? [cmd %x, magic %x != %x]\n",
572                        command,
573                        _IOC_TYPE(command),
574                        ORANGEFS_DEV_MAGIC);
575                return -EINVAL;
576        }
577        /* and valid ioctl commands */
578        if (_IOC_NR(command) >= ORANGEFS_DEV_MAXNR || _IOC_NR(command) <= 0) {
579                gossip_err("Invalid ioctl command number [%d >= %d]\n",
580                           _IOC_NR(command), ORANGEFS_DEV_MAXNR);
581                return -ENOIOCTLCMD;
582        }
583        return 0;
584}
585
586static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
587{
588        static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
589        static __s32 max_up_size = MAX_DEV_REQ_UPSIZE;
590        static __s32 max_down_size = MAX_DEV_REQ_DOWNSIZE;
591        struct ORANGEFS_dev_map_desc user_desc;
592        int ret = 0;
593        int upstream_kmod = 1;
594        struct orangefs_sb_info_s *orangefs_sb;
595
596        /* mtmoore: add locking here */
597
598        switch (command) {
599        case ORANGEFS_DEV_GET_MAGIC:
600                return ((put_user(magic, (__s32 __user *) arg) == -EFAULT) ?
601                        -EIO :
602                        0);
603        case ORANGEFS_DEV_GET_MAX_UPSIZE:
604                return ((put_user(max_up_size,
605                                  (__s32 __user *) arg) == -EFAULT) ?
606                                        -EIO :
607                                        0);
608        case ORANGEFS_DEV_GET_MAX_DOWNSIZE:
609                return ((put_user(max_down_size,
610                                  (__s32 __user *) arg) == -EFAULT) ?
611                                        -EIO :
612                                        0);
613        case ORANGEFS_DEV_MAP:
614                ret = copy_from_user(&user_desc,
615                                     (struct ORANGEFS_dev_map_desc __user *)
616                                     arg,
617                                     sizeof(struct ORANGEFS_dev_map_desc));
618                /* WTF -EIO and not -EFAULT? */
619                return ret ? -EIO : orangefs_bufmap_initialize(&user_desc);
620        case ORANGEFS_DEV_REMOUNT_ALL:
621                gossip_debug(GOSSIP_DEV_DEBUG,
622                             "%s: got ORANGEFS_DEV_REMOUNT_ALL\n",
623                             __func__);
624
625                /*
626                 * remount all mounted orangefs volumes to regain the lost
627                 * dynamic mount tables (if any) -- NOTE: this is done
628                 * without keeping the superblock list locked due to the
629                 * upcall/downcall waiting.  also, the request mutex is
630                 * used to ensure that no operations will be serviced until
631                 * all of the remounts are serviced (to avoid ops between
632                 * mounts to fail)
633                 */
634                ret = mutex_lock_interruptible(&orangefs_request_mutex);
635                if (ret < 0)
636                        return ret;
637                gossip_debug(GOSSIP_DEV_DEBUG,
638                             "%s: priority remount in progress\n",
639                             __func__);
640                spin_lock(&orangefs_superblocks_lock);
641                list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
642                        /*
643                         * We have to drop the spinlock, so entries can be
644                         * removed.  They can't be freed, though, so we just
645                         * keep the forward pointers and zero the back ones -
646                         * that way we can get to the rest of the list.
647                         */
648                        if (!orangefs_sb->list.prev)
649                                continue;
650                        gossip_debug(GOSSIP_DEV_DEBUG,
651                                     "%s: Remounting SB %p\n",
652                                     __func__,
653                                     orangefs_sb);
654
655                        spin_unlock(&orangefs_superblocks_lock);
656                        ret = orangefs_remount(orangefs_sb);
657                        spin_lock(&orangefs_superblocks_lock);
658                        if (ret) {
659                                gossip_debug(GOSSIP_DEV_DEBUG,
660                                             "SB %p remount failed\n",
661                                             orangefs_sb);
662                                break;
663                        }
664                }
665                spin_unlock(&orangefs_superblocks_lock);
666                gossip_debug(GOSSIP_DEV_DEBUG,
667                             "%s: priority remount complete\n",
668                             __func__);
669                mutex_unlock(&orangefs_request_mutex);
670                return ret;
671
672        case ORANGEFS_DEV_UPSTREAM:
673                ret = copy_to_user((void __user *)arg,
674                                    &upstream_kmod,
675                                    sizeof(upstream_kmod));
676
677                if (ret != 0)
678                        return -EIO;
679                else
680                        return ret;
681
682        case ORANGEFS_DEV_CLIENT_MASK:
683                return orangefs_debugfs_new_client_mask((void __user *)arg);
684        case ORANGEFS_DEV_CLIENT_STRING:
685                return orangefs_debugfs_new_client_string((void __user *)arg);
686        case ORANGEFS_DEV_DEBUG:
687                return orangefs_debugfs_new_debug((void __user *)arg);
688        default:
689                return -ENOIOCTLCMD;
690        }
691        return -ENOIOCTLCMD;
692}
693
694static long orangefs_devreq_ioctl(struct file *file,
695                               unsigned int command, unsigned long arg)
696{
697        long ret;
698
699        /* Check for properly constructed commands */
700        ret = check_ioctl_command(command);
701        if (ret < 0)
702                return (int)ret;
703
704        return (int)dispatch_ioctl_command(command, arg);
705}
706
707#ifdef CONFIG_COMPAT            /* CONFIG_COMPAT is in .config */
708
709/*  Compat structure for the ORANGEFS_DEV_MAP ioctl */
710struct ORANGEFS_dev_map_desc32 {
711        compat_uptr_t ptr;
712        __s32 total_size;
713        __s32 size;
714        __s32 count;
715};
716
717static unsigned long translate_dev_map26(unsigned long args, long *error)
718{
719        struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args;
720        /*
721         * Depending on the architecture, allocate some space on the
722         * user-call-stack based on our expected layout.
723         */
724        struct ORANGEFS_dev_map_desc __user *p =
725            compat_alloc_user_space(sizeof(*p));
726        compat_uptr_t addr;
727
728        *error = 0;
729        /* get the ptr from the 32 bit user-space */
730        if (get_user(addr, &p32->ptr))
731                goto err;
732        /* try to put that into a 64-bit layout */
733        if (put_user(compat_ptr(addr), &p->ptr))
734                goto err;
735        /* copy the remaining fields */
736        if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32)))
737                goto err;
738        if (copy_in_user(&p->size, &p32->size, sizeof(__s32)))
739                goto err;
740        if (copy_in_user(&p->count, &p32->count, sizeof(__s32)))
741                goto err;
742        return (unsigned long)p;
743err:
744        *error = -EFAULT;
745        return 0;
746}
747
748/*
749 * 32 bit user-space apps' ioctl handlers when kernel modules
750 * is compiled as a 64 bit one
751 */
752static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd,
753                                      unsigned long args)
754{
755        long ret;
756        unsigned long arg = args;
757
758        /* Check for properly constructed commands */
759        ret = check_ioctl_command(cmd);
760        if (ret < 0)
761                return ret;
762        if (cmd == ORANGEFS_DEV_MAP) {
763                /*
764                 * convert the arguments to what we expect internally
765                 * in kernel space
766                 */
767                arg = translate_dev_map26(args, &ret);
768                if (ret < 0) {
769                        gossip_err("Could not translate dev map\n");
770                        return ret;
771                }
772        }
773        /* no other ioctl requires translation */
774        return dispatch_ioctl_command(cmd, arg);
775}
776
777#endif /* CONFIG_COMPAT is in .config */
778
779/* the assigned character device major number */
780static int orangefs_dev_major;
781
782/*
783 * Initialize orangefs device specific state:
784 * Must be called at module load time only
785 */
786int orangefs_dev_init(void)
787{
788        /* register orangefs-req device  */
789        orangefs_dev_major = register_chrdev(0,
790                                          ORANGEFS_REQDEVICE_NAME,
791                                          &orangefs_devreq_file_operations);
792        if (orangefs_dev_major < 0) {
793                gossip_debug(GOSSIP_DEV_DEBUG,
794                             "Failed to register /dev/%s (error %d)\n",
795                             ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
796                return orangefs_dev_major;
797        }
798
799        gossip_debug(GOSSIP_DEV_DEBUG,
800                     "*** /dev/%s character device registered ***\n",
801                     ORANGEFS_REQDEVICE_NAME);
802        gossip_debug(GOSSIP_DEV_DEBUG, "'mknod /dev/%s c %d 0'.\n",
803                     ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
804        return 0;
805}
806
807void orangefs_dev_cleanup(void)
808{
809        unregister_chrdev(orangefs_dev_major, ORANGEFS_REQDEVICE_NAME);
810        gossip_debug(GOSSIP_DEV_DEBUG,
811                     "*** /dev/%s character device unregistered ***\n",
812                     ORANGEFS_REQDEVICE_NAME);
813}
814
815static unsigned int orangefs_devreq_poll(struct file *file,
816                                      struct poll_table_struct *poll_table)
817{
818        int poll_revent_mask = 0;
819
820        poll_wait(file, &orangefs_request_list_waitq, poll_table);
821
822        if (!list_empty(&orangefs_request_list))
823                poll_revent_mask |= POLL_IN;
824        return poll_revent_mask;
825}
826
827const struct file_operations orangefs_devreq_file_operations = {
828        .owner = THIS_MODULE,
829        .read = orangefs_devreq_read,
830        .write_iter = orangefs_devreq_write_iter,
831        .open = orangefs_devreq_open,
832        .release = orangefs_devreq_release,
833        .unlocked_ioctl = orangefs_devreq_ioctl,
834
835#ifdef CONFIG_COMPAT            /* CONFIG_COMPAT is in .config */
836        .compat_ioctl = orangefs_devreq_compat_ioctl,
837#endif
838        .poll = orangefs_devreq_poll
839};
Note: See TracBrowser for help on using the repository browser.