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

Last change on this file since 31885 was 31885, checked in by brainslayer, 2 months ago

update

File size: 22.7 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 or unmounted.  It is possible for
212                         * a filesystem we don't know about to be unmounted if
213                         * it fails to mount in the kernel after userspace has
214                         * been sent the mount request.
215                         */
216                        /* XXX: is there a better way to detect this? */
217                        } else if (ret == -1 &&
218                                   !(op->upcall.type ==
219                                        ORANGEFS_VFS_OP_FS_MOUNT ||
220                                     op->upcall.type ==
221                                        ORANGEFS_VFS_OP_GETATTR ||
222                                     op->upcall.type ==
223                                        ORANGEFS_VFS_OP_FS_UMOUNT)) {
224                                gossip_debug(GOSSIP_DEV_DEBUG,
225                                    "orangefs: skipping op tag %llu %s\n",
226                                    llu(op->tag), get_opname_string(op));
227                                gossip_err(
228                                    "orangefs: ERROR: fs_mount_pending %d\n",
229                                    fsid);
230                                spin_unlock(&op->lock);
231                                continue;
232                        }
233                }
234                /*
235                 * Either this op does not pertain to a filesystem, is mounting
236                 * a filesystem, or pertains to a mounted filesystem. Let it
237                 * through.
238                 */
239                cur_op = op;
240                break;
241        }
242
243        /*
244         * At this point we either have a valid op and can continue or have not
245         * found an op and must ask the client to try again later.
246         */
247        if (!cur_op) {
248                spin_unlock(&orangefs_request_list_lock);
249                return -EAGAIN;
250        }
251
252        gossip_debug(GOSSIP_DEV_DEBUG, "%s: reading op tag %llu %s\n",
253                     __func__,
254                     llu(cur_op->tag),
255                     get_opname_string(cur_op));
256
257        /*
258         * Such an op should never be on the list in the first place. If so, we
259         * will abort.
260         */
261        if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) {
262                gossip_err("orangefs: ERROR: Current op already queued.\n");
263                list_del_init(&cur_op->list);
264                spin_unlock(&cur_op->lock);
265                spin_unlock(&orangefs_request_list_lock);
266                return -EAGAIN;
267        }
268
269        list_del_init(&cur_op->list);
270        spin_unlock(&orangefs_request_list_lock);
271
272        spin_unlock(&cur_op->lock);
273
274        /* Push the upcall out. */
275        ret = copy_to_user(buf, &proto_ver, sizeof(__s32));
276        if (ret != 0)
277                goto error;
278        ret = copy_to_user(buf+sizeof(__s32), &magic, sizeof(__s32));
279        if (ret != 0)
280                goto error;
281        ret = copy_to_user(buf+2 * sizeof(__s32), &cur_op->tag, sizeof(__u64));
282        if (ret != 0)
283                goto error;
284        ret = copy_to_user(buf+2*sizeof(__s32)+sizeof(__u64), &cur_op->upcall,
285                           sizeof(struct orangefs_upcall_s));
286        if (ret != 0)
287                goto error;
288
289        spin_lock(&orangefs_htable_ops_in_progress_lock);
290        spin_lock(&cur_op->lock);
291        if (unlikely(op_state_given_up(cur_op))) {
292                spin_unlock(&cur_op->lock);
293                spin_unlock(&orangefs_htable_ops_in_progress_lock);
294                complete(&cur_op->waitq);
295                goto restart;
296        }
297
298        /*
299         * Set the operation to be in progress and move it between lists since
300         * it has been sent to the client.
301         */
302        set_op_state_inprogress(cur_op);
303        gossip_debug(GOSSIP_DEV_DEBUG,
304                     "%s: 1 op:%s: op_state:%d: process:%s:\n",
305                     __func__,
306                     get_opname_string(cur_op),
307                     cur_op->op_state,
308                     current->comm);
309        orangefs_devreq_add_op(cur_op);
310        spin_unlock(&cur_op->lock);
311        spin_unlock(&orangefs_htable_ops_in_progress_lock);
312
313        /* The client only asks to read one size buffer. */
314        return MAX_DEV_REQ_UPSIZE;
315error:
316        /*
317         * We were unable to copy the op data to the client. Put the op back in
318         * list. If client has crashed, the op will be purged later when the
319         * device is released.
320         */
321        gossip_err("orangefs: Failed to copy data to user space\n");
322        spin_lock(&orangefs_request_list_lock);
323        spin_lock(&cur_op->lock);
324        if (likely(!op_state_given_up(cur_op))) {
325                set_op_state_waiting(cur_op);
326                gossip_debug(GOSSIP_DEV_DEBUG,
327                             "%s: 2 op:%s: op_state:%d: process:%s:\n",
328                             __func__,
329                             get_opname_string(cur_op),
330                             cur_op->op_state,
331                             current->comm);
332                list_add(&cur_op->list, &orangefs_request_list);
333                spin_unlock(&cur_op->lock);
334        } else {
335                spin_unlock(&cur_op->lock);
336                complete(&cur_op->waitq);
337        }
338        spin_unlock(&orangefs_request_list_lock);
339        return -EFAULT;
340}
341
342/*
343 * Function for writev() callers into the device.
344 *
345 * Userspace should have written:
346 *  - __u32 version
347 *  - __u32 magic
348 *  - __u64 tag
349 *  - struct orangefs_downcall_s
350 *  - trailer buffer (in the case of READDIR operations)
351 */
352static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
353                                      struct iov_iter *iter)
354{
355        ssize_t ret;
356        struct orangefs_kernel_op_s *op = NULL;
357        struct {
358                __u32 version;
359                __u32 magic;
360                __u64 tag;
361        } head;
362        int total = ret = iov_iter_count(iter);
363        int n;
364        int downcall_size = sizeof(struct orangefs_downcall_s);
365        int head_size = sizeof(head);
366
367        gossip_debug(GOSSIP_DEV_DEBUG, "%s: total:%d: ret:%zd:\n",
368                     __func__,
369                     total,
370                     ret);
371
372        if (total < MAX_DEV_REQ_DOWNSIZE) {
373                gossip_err("%s: total:%d: must be at least:%u:\n",
374                           __func__,
375                           total,
376                           (unsigned int) MAX_DEV_REQ_DOWNSIZE);
377                return -EFAULT;
378        }
379     
380        n = copy_from_iter(&head, head_size, iter);
381        if (n < head_size) {
382                gossip_err("%s: failed to copy head.\n", __func__);
383                return -EFAULT;
384        }
385
386        if (head.version < ORANGEFS_MINIMUM_USERSPACE_VERSION) {
387                gossip_err("%s: userspace claims version"
388                           "%d, minimum version required: %d.\n",
389                           __func__,
390                           head.version,
391                           ORANGEFS_MINIMUM_USERSPACE_VERSION);
392                return -EPROTO;
393        }
394
395        if (head.magic != ORANGEFS_DEVREQ_MAGIC) {
396                gossip_err("Error: Device magic number does not match.\n");
397                return -EPROTO;
398        }
399
400        if (!orangefs_userspace_version) {
401                orangefs_userspace_version = head.version;
402        } else if (orangefs_userspace_version != head.version) {
403                gossip_err("Error: userspace version changes\n");
404                return -EPROTO;
405        }
406
407        /* remove the op from the in progress hash table */
408        op = orangefs_devreq_remove_op(head.tag);
409        if (!op) {
410                gossip_debug(GOSSIP_DEV_DEBUG,
411                             "%s: No one's waiting for tag %llu\n",
412                             __func__, llu(head.tag));
413                return ret;
414        }
415
416        n = copy_from_iter(&op->downcall, downcall_size, iter);
417        if (n != downcall_size) {
418                gossip_err("%s: failed to copy downcall.\n", __func__);
419                goto Efault;
420        }
421
422        if (op->downcall.status)
423                goto wakeup;
424
425        /*
426         * We've successfully peeled off the head and the downcall.
427         * Something has gone awry if total doesn't equal the
428         * sum of head_size, downcall_size and trailer_size.
429         */
430        if ((head_size + downcall_size + op->downcall.trailer_size) != total) {
431                gossip_err("%s: funky write, head_size:%d"
432                           ": downcall_size:%d: trailer_size:%lld"
433                           ": total size:%d:\n",
434                           __func__,
435                           head_size,
436                           downcall_size,
437                           op->downcall.trailer_size,
438                           total);
439                goto Efault;
440        }
441
442        /* Only READDIR operations should have trailers. */
443        if ((op->downcall.type != ORANGEFS_VFS_OP_READDIR) &&
444            (op->downcall.trailer_size != 0)) {
445                gossip_err("%s: %x operation with trailer.",
446                           __func__,
447                           op->downcall.type);
448                goto Efault;
449        }
450
451        /* READDIR operations should always have trailers. */
452        if ((op->downcall.type == ORANGEFS_VFS_OP_READDIR) &&
453            (op->downcall.trailer_size == 0)) {
454                gossip_err("%s: %x operation with no trailer.",
455                           __func__,
456                           op->downcall.type);
457                goto Efault;
458        }
459
460        if (op->downcall.type != ORANGEFS_VFS_OP_READDIR)
461                goto wakeup;
462
463        op->downcall.trailer_buf =
464                vmalloc(op->downcall.trailer_size);
465        if (op->downcall.trailer_buf == NULL) {
466                gossip_err("%s: failed trailer vmalloc.\n",
467                           __func__);
468                goto Enomem;
469        }
470        memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size);
471        n = copy_from_iter(op->downcall.trailer_buf,
472                           op->downcall.trailer_size,
473                           iter);
474        if (n != op->downcall.trailer_size) {
475                gossip_err("%s: failed to copy trailer.\n", __func__);
476                vfree(op->downcall.trailer_buf);
477                goto Efault;
478        }
479
480wakeup:
481        /*
482         * Return to vfs waitqueue, and back to service_operation
483         * through wait_for_matching_downcall.
484         */
485        spin_lock(&op->lock);
486        if (unlikely(op_is_cancel(op))) {
487                spin_unlock(&op->lock);
488                put_cancel(op);
489        } else if (unlikely(op_state_given_up(op))) {
490                spin_unlock(&op->lock);
491                complete(&op->waitq);
492        } else {
493                set_op_state_serviced(op);
494                gossip_debug(GOSSIP_DEV_DEBUG,
495                             "%s: op:%s: op_state:%d: process:%s:\n",
496                             __func__,
497                             get_opname_string(op),
498                             op->op_state,
499                             current->comm);
500                spin_unlock(&op->lock);
501        }
502        return ret;
503
504Efault:
505        op->downcall.status = -(ORANGEFS_ERROR_BIT | 9);
506        ret = -EFAULT;
507        goto wakeup;
508
509Enomem:
510        op->downcall.status = -(ORANGEFS_ERROR_BIT | 8);
511        ret = -ENOMEM;
512        goto wakeup;
513}
514
515/*
516 * NOTE: gets called when the last reference to this device is dropped.
517 * Using the open_access_count variable, we enforce a reference count
518 * on this file so that it can be opened by only one process at a time.
519 * the devreq_mutex is used to make sure all i/o has completed
520 * before we call orangefs_bufmap_finalize, and similar such tricky
521 * situations
522 */
523static int orangefs_devreq_release(struct inode *inode, struct file *file)
524{
525        int unmounted = 0;
526
527        gossip_debug(GOSSIP_DEV_DEBUG,
528                     "%s:pvfs2-client-core: exiting, closing device\n",
529                     __func__);
530
531        mutex_lock(&devreq_mutex);
532        orangefs_bufmap_finalize();
533
534        open_access_count = -1;
535
536        unmounted = mark_all_pending_mounts();
537        gossip_debug(GOSSIP_DEV_DEBUG, "ORANGEFS Device Close: Filesystem(s) %s\n",
538                     (unmounted ? "UNMOUNTED" : "MOUNTED"));
539
540        purge_waiting_ops();
541        purge_inprogress_ops();
542
543        orangefs_bufmap_run_down();
544
545        gossip_debug(GOSSIP_DEV_DEBUG,
546                     "pvfs2-client-core: device close complete\n");
547        open_access_count = 0;
548        orangefs_userspace_version = 0;
549        mutex_unlock(&devreq_mutex);
550        return 0;
551}
552
553int is_daemon_in_service(void)
554{
555        int in_service;
556
557        /*
558         * What this function does is checks if client-core is alive
559         * based on the access count we maintain on the device.
560         */
561        mutex_lock(&devreq_mutex);
562        in_service = open_access_count == 1 ? 0 : -EIO;
563        mutex_unlock(&devreq_mutex);
564        return in_service;
565}
566
567bool __is_daemon_in_service(void)
568{
569        return open_access_count == 1;
570}
571
572static inline long check_ioctl_command(unsigned int command)
573{
574        /* Check for valid ioctl codes */
575        if (_IOC_TYPE(command) != ORANGEFS_DEV_MAGIC) {
576                gossip_err("device ioctl magic numbers don't match! Did you rebuild pvfs2-client-core/libpvfs2? [cmd %x, magic %x != %x]\n",
577                        command,
578                        _IOC_TYPE(command),
579                        ORANGEFS_DEV_MAGIC);
580                return -EINVAL;
581        }
582        /* and valid ioctl commands */
583        if (_IOC_NR(command) >= ORANGEFS_DEV_MAXNR || _IOC_NR(command) <= 0) {
584                gossip_err("Invalid ioctl command number [%d >= %d]\n",
585                           _IOC_NR(command), ORANGEFS_DEV_MAXNR);
586                return -ENOIOCTLCMD;
587        }
588        return 0;
589}
590
591static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
592{
593        static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
594        static __s32 max_up_size = MAX_DEV_REQ_UPSIZE;
595        static __s32 max_down_size = MAX_DEV_REQ_DOWNSIZE;
596        struct ORANGEFS_dev_map_desc user_desc;
597        int ret = 0;
598        int upstream_kmod = 1;
599        struct orangefs_sb_info_s *orangefs_sb;
600
601        /* mtmoore: add locking here */
602
603        switch (command) {
604        case ORANGEFS_DEV_GET_MAGIC:
605                return ((put_user(magic, (__s32 __user *) arg) == -EFAULT) ?
606                        -EIO :
607                        0);
608        case ORANGEFS_DEV_GET_MAX_UPSIZE:
609                return ((put_user(max_up_size,
610                                  (__s32 __user *) arg) == -EFAULT) ?
611                                        -EIO :
612                                        0);
613        case ORANGEFS_DEV_GET_MAX_DOWNSIZE:
614                return ((put_user(max_down_size,
615                                  (__s32 __user *) arg) == -EFAULT) ?
616                                        -EIO :
617                                        0);
618        case ORANGEFS_DEV_MAP:
619                ret = copy_from_user(&user_desc,
620                                     (struct ORANGEFS_dev_map_desc __user *)
621                                     arg,
622                                     sizeof(struct ORANGEFS_dev_map_desc));
623                /* WTF -EIO and not -EFAULT? */
624                return ret ? -EIO : orangefs_bufmap_initialize(&user_desc);
625        case ORANGEFS_DEV_REMOUNT_ALL:
626                gossip_debug(GOSSIP_DEV_DEBUG,
627                             "%s: got ORANGEFS_DEV_REMOUNT_ALL\n",
628                             __func__);
629
630                /*
631                 * remount all mounted orangefs volumes to regain the lost
632                 * dynamic mount tables (if any) -- NOTE: this is done
633                 * without keeping the superblock list locked due to the
634                 * upcall/downcall waiting.  also, the request mutex is
635                 * used to ensure that no operations will be serviced until
636                 * all of the remounts are serviced (to avoid ops between
637                 * mounts to fail)
638                 */
639                ret = mutex_lock_interruptible(&orangefs_request_mutex);
640                if (ret < 0)
641                        return ret;
642                gossip_debug(GOSSIP_DEV_DEBUG,
643                             "%s: priority remount in progress\n",
644                             __func__);
645                spin_lock(&orangefs_superblocks_lock);
646                list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
647                        /*
648                         * We have to drop the spinlock, so entries can be
649                         * removed.  They can't be freed, though, so we just
650                         * keep the forward pointers and zero the back ones -
651                         * that way we can get to the rest of the list.
652                         */
653                        if (!orangefs_sb->list.prev)
654                                continue;
655                        gossip_debug(GOSSIP_DEV_DEBUG,
656                                     "%s: Remounting SB %p\n",
657                                     __func__,
658                                     orangefs_sb);
659
660                        spin_unlock(&orangefs_superblocks_lock);
661                        ret = orangefs_remount(orangefs_sb);
662                        spin_lock(&orangefs_superblocks_lock);
663                        if (ret) {
664                                gossip_debug(GOSSIP_DEV_DEBUG,
665                                             "SB %p remount failed\n",
666                                             orangefs_sb);
667                                break;
668                        }
669                }
670                spin_unlock(&orangefs_superblocks_lock);
671                gossip_debug(GOSSIP_DEV_DEBUG,
672                             "%s: priority remount complete\n",
673                             __func__);
674                mutex_unlock(&orangefs_request_mutex);
675                return ret;
676
677        case ORANGEFS_DEV_UPSTREAM:
678                ret = copy_to_user((void __user *)arg,
679                                    &upstream_kmod,
680                                    sizeof(upstream_kmod));
681
682                if (ret != 0)
683                        return -EIO;
684                else
685                        return ret;
686
687        case ORANGEFS_DEV_CLIENT_MASK:
688                return orangefs_debugfs_new_client_mask((void __user *)arg);
689        case ORANGEFS_DEV_CLIENT_STRING:
690                return orangefs_debugfs_new_client_string((void __user *)arg);
691        case ORANGEFS_DEV_DEBUG:
692                return orangefs_debugfs_new_debug((void __user *)arg);
693        default:
694                return -ENOIOCTLCMD;
695        }
696        return -ENOIOCTLCMD;
697}
698
699static long orangefs_devreq_ioctl(struct file *file,
700                               unsigned int command, unsigned long arg)
701{
702        long ret;
703
704        /* Check for properly constructed commands */
705        ret = check_ioctl_command(command);
706        if (ret < 0)
707                return (int)ret;
708
709        return (int)dispatch_ioctl_command(command, arg);
710}
711
712#ifdef CONFIG_COMPAT            /* CONFIG_COMPAT is in .config */
713
714/*  Compat structure for the ORANGEFS_DEV_MAP ioctl */
715struct ORANGEFS_dev_map_desc32 {
716        compat_uptr_t ptr;
717        __s32 total_size;
718        __s32 size;
719        __s32 count;
720};
721
722static unsigned long translate_dev_map26(unsigned long args, long *error)
723{
724        struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args;
725        /*
726         * Depending on the architecture, allocate some space on the
727         * user-call-stack based on our expected layout.
728         */
729        struct ORANGEFS_dev_map_desc __user *p =
730            compat_alloc_user_space(sizeof(*p));
731        compat_uptr_t addr;
732
733        *error = 0;
734        /* get the ptr from the 32 bit user-space */
735        if (get_user(addr, &p32->ptr))
736                goto err;
737        /* try to put that into a 64-bit layout */
738        if (put_user(compat_ptr(addr), &p->ptr))
739                goto err;
740        /* copy the remaining fields */
741        if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32)))
742                goto err;
743        if (copy_in_user(&p->size, &p32->size, sizeof(__s32)))
744                goto err;
745        if (copy_in_user(&p->count, &p32->count, sizeof(__s32)))
746                goto err;
747        return (unsigned long)p;
748err:
749        *error = -EFAULT;
750        return 0;
751}
752
753/*
754 * 32 bit user-space apps' ioctl handlers when kernel modules
755 * is compiled as a 64 bit one
756 */
757static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd,
758                                      unsigned long args)
759{
760        long ret;
761        unsigned long arg = args;
762
763        /* Check for properly constructed commands */
764        ret = check_ioctl_command(cmd);
765        if (ret < 0)
766                return ret;
767        if (cmd == ORANGEFS_DEV_MAP) {
768                /*
769                 * convert the arguments to what we expect internally
770                 * in kernel space
771                 */
772                arg = translate_dev_map26(args, &ret);
773                if (ret < 0) {
774                        gossip_err("Could not translate dev map\n");
775                        return ret;
776                }
777        }
778        /* no other ioctl requires translation */
779        return dispatch_ioctl_command(cmd, arg);
780}
781
782#endif /* CONFIG_COMPAT is in .config */
783
784/* the assigned character device major number */
785static int orangefs_dev_major;
786
787/*
788 * Initialize orangefs device specific state:
789 * Must be called at module load time only
790 */
791int orangefs_dev_init(void)
792{
793        /* register orangefs-req device  */
794        orangefs_dev_major = register_chrdev(0,
795                                          ORANGEFS_REQDEVICE_NAME,
796                                          &orangefs_devreq_file_operations);
797        if (orangefs_dev_major < 0) {
798                gossip_debug(GOSSIP_DEV_DEBUG,
799                             "Failed to register /dev/%s (error %d)\n",
800                             ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
801                return orangefs_dev_major;
802        }
803
804        gossip_debug(GOSSIP_DEV_DEBUG,
805                     "*** /dev/%s character device registered ***\n",
806                     ORANGEFS_REQDEVICE_NAME);
807        gossip_debug(GOSSIP_DEV_DEBUG, "'mknod /dev/%s c %d 0'.\n",
808                     ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
809        return 0;
810}
811
812void orangefs_dev_cleanup(void)
813{
814        unregister_chrdev(orangefs_dev_major, ORANGEFS_REQDEVICE_NAME);
815        gossip_debug(GOSSIP_DEV_DEBUG,
816                     "*** /dev/%s character device unregistered ***\n",
817                     ORANGEFS_REQDEVICE_NAME);
818}
819
820static unsigned int orangefs_devreq_poll(struct file *file,
821                                      struct poll_table_struct *poll_table)
822{
823        int poll_revent_mask = 0;
824
825        poll_wait(file, &orangefs_request_list_waitq, poll_table);
826
827        if (!list_empty(&orangefs_request_list))
828                poll_revent_mask |= POLL_IN;
829        return poll_revent_mask;
830}
831
832const struct file_operations orangefs_devreq_file_operations = {
833        .owner = THIS_MODULE,
834        .read = orangefs_devreq_read,
835        .write_iter = orangefs_devreq_write_iter,
836        .open = orangefs_devreq_open,
837        .release = orangefs_devreq_release,
838        .unlocked_ioctl = orangefs_devreq_ioctl,
839
840#ifdef CONFIG_COMPAT            /* CONFIG_COMPAT is in .config */
841        .compat_ioctl = orangefs_devreq_compat_ioctl,
842#endif
843        .poll = orangefs_devreq_poll
844};
Note: See TracBrowser for help on using the repository browser.