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

Last change on this file since 31574 was 31574, checked in by brainslayer, 7 weeks ago

kernel 4.9 update

File size: 22.4 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_err("WARNING: No one's waiting for tag %llu\n",
406                           llu(head.tag));
407                return ret;
408        }
409
410        n = copy_from_iter(&op->downcall, downcall_size, iter);
411        if (n != downcall_size) {
412                gossip_err("%s: failed to copy downcall.\n", __func__);
413                goto Efault;
414        }
415
416        if (op->downcall.status)
417                goto wakeup;
418
419        /*
420         * We've successfully peeled off the head and the downcall.
421         * Something has gone awry if total doesn't equal the
422         * sum of head_size, downcall_size and trailer_size.
423         */
424        if ((head_size + downcall_size + op->downcall.trailer_size) != total) {
425                gossip_err("%s: funky write, head_size:%d"
426                           ": downcall_size:%d: trailer_size:%lld"
427                           ": total size:%d:\n",
428                           __func__,
429                           head_size,
430                           downcall_size,
431                           op->downcall.trailer_size,
432                           total);
433                goto Efault;
434        }
435
436        /* Only READDIR operations should have trailers. */
437        if ((op->downcall.type != ORANGEFS_VFS_OP_READDIR) &&
438            (op->downcall.trailer_size != 0)) {
439                gossip_err("%s: %x operation with trailer.",
440                           __func__,
441                           op->downcall.type);
442                goto Efault;
443        }
444
445        /* READDIR operations should always have trailers. */
446        if ((op->downcall.type == ORANGEFS_VFS_OP_READDIR) &&
447            (op->downcall.trailer_size == 0)) {
448                gossip_err("%s: %x operation with no trailer.",
449                           __func__,
450                           op->downcall.type);
451                goto Efault;
452        }
453
454        if (op->downcall.type != ORANGEFS_VFS_OP_READDIR)
455                goto wakeup;
456
457        op->downcall.trailer_buf =
458                vmalloc(op->downcall.trailer_size);
459        if (op->downcall.trailer_buf == NULL) {
460                gossip_err("%s: failed trailer vmalloc.\n",
461                           __func__);
462                goto Enomem;
463        }
464        memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size);
465        n = copy_from_iter(op->downcall.trailer_buf,
466                           op->downcall.trailer_size,
467                           iter);
468        if (n != op->downcall.trailer_size) {
469                gossip_err("%s: failed to copy trailer.\n", __func__);
470                vfree(op->downcall.trailer_buf);
471                goto Efault;
472        }
473
474wakeup:
475        /*
476         * Return to vfs waitqueue, and back to service_operation
477         * through wait_for_matching_downcall.
478         */
479        spin_lock(&op->lock);
480        if (unlikely(op_is_cancel(op))) {
481                spin_unlock(&op->lock);
482                put_cancel(op);
483        } else if (unlikely(op_state_given_up(op))) {
484                spin_unlock(&op->lock);
485                complete(&op->waitq);
486        } else {
487                set_op_state_serviced(op);
488                gossip_debug(GOSSIP_DEV_DEBUG,
489                             "%s: op:%s: op_state:%d: process:%s:\n",
490                             __func__,
491                             get_opname_string(op),
492                             op->op_state,
493                             current->comm);
494                spin_unlock(&op->lock);
495        }
496        return ret;
497
498Efault:
499        op->downcall.status = -(ORANGEFS_ERROR_BIT | 9);
500        ret = -EFAULT;
501        goto wakeup;
502
503Enomem:
504        op->downcall.status = -(ORANGEFS_ERROR_BIT | 8);
505        ret = -ENOMEM;
506        goto wakeup;
507}
508
509/*
510 * NOTE: gets called when the last reference to this device is dropped.
511 * Using the open_access_count variable, we enforce a reference count
512 * on this file so that it can be opened by only one process at a time.
513 * the devreq_mutex is used to make sure all i/o has completed
514 * before we call orangefs_bufmap_finalize, and similar such tricky
515 * situations
516 */
517static int orangefs_devreq_release(struct inode *inode, struct file *file)
518{
519        int unmounted = 0;
520
521        gossip_debug(GOSSIP_DEV_DEBUG,
522                     "%s:pvfs2-client-core: exiting, closing device\n",
523                     __func__);
524
525        mutex_lock(&devreq_mutex);
526        orangefs_bufmap_finalize();
527
528        open_access_count = -1;
529
530        unmounted = mark_all_pending_mounts();
531        gossip_debug(GOSSIP_DEV_DEBUG, "ORANGEFS Device Close: Filesystem(s) %s\n",
532                     (unmounted ? "UNMOUNTED" : "MOUNTED"));
533
534        purge_waiting_ops();
535        purge_inprogress_ops();
536
537        orangefs_bufmap_run_down();
538
539        gossip_debug(GOSSIP_DEV_DEBUG,
540                     "pvfs2-client-core: device close complete\n");
541        open_access_count = 0;
542        orangefs_userspace_version = 0;
543        mutex_unlock(&devreq_mutex);
544        return 0;
545}
546
547int is_daemon_in_service(void)
548{
549        int in_service;
550
551        /*
552         * What this function does is checks if client-core is alive
553         * based on the access count we maintain on the device.
554         */
555        mutex_lock(&devreq_mutex);
556        in_service = open_access_count == 1 ? 0 : -EIO;
557        mutex_unlock(&devreq_mutex);
558        return in_service;
559}
560
561bool __is_daemon_in_service(void)
562{
563        return open_access_count == 1;
564}
565
566static inline long check_ioctl_command(unsigned int command)
567{
568        /* Check for valid ioctl codes */
569        if (_IOC_TYPE(command) != ORANGEFS_DEV_MAGIC) {
570                gossip_err("device ioctl magic numbers don't match! Did you rebuild pvfs2-client-core/libpvfs2? [cmd %x, magic %x != %x]\n",
571                        command,
572                        _IOC_TYPE(command),
573                        ORANGEFS_DEV_MAGIC);
574                return -EINVAL;
575        }
576        /* and valid ioctl commands */
577        if (_IOC_NR(command) >= ORANGEFS_DEV_MAXNR || _IOC_NR(command) <= 0) {
578                gossip_err("Invalid ioctl command number [%d >= %d]\n",
579                           _IOC_NR(command), ORANGEFS_DEV_MAXNR);
580                return -ENOIOCTLCMD;
581        }
582        return 0;
583}
584
585static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
586{
587        static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
588        static __s32 max_up_size = MAX_DEV_REQ_UPSIZE;
589        static __s32 max_down_size = MAX_DEV_REQ_DOWNSIZE;
590        struct ORANGEFS_dev_map_desc user_desc;
591        int ret = 0;
592        int upstream_kmod = 1;
593        struct orangefs_sb_info_s *orangefs_sb;
594
595        /* mtmoore: add locking here */
596
597        switch (command) {
598        case ORANGEFS_DEV_GET_MAGIC:
599                return ((put_user(magic, (__s32 __user *) arg) == -EFAULT) ?
600                        -EIO :
601                        0);
602        case ORANGEFS_DEV_GET_MAX_UPSIZE:
603                return ((put_user(max_up_size,
604                                  (__s32 __user *) arg) == -EFAULT) ?
605                                        -EIO :
606                                        0);
607        case ORANGEFS_DEV_GET_MAX_DOWNSIZE:
608                return ((put_user(max_down_size,
609                                  (__s32 __user *) arg) == -EFAULT) ?
610                                        -EIO :
611                                        0);
612        case ORANGEFS_DEV_MAP:
613                ret = copy_from_user(&user_desc,
614                                     (struct ORANGEFS_dev_map_desc __user *)
615                                     arg,
616                                     sizeof(struct ORANGEFS_dev_map_desc));
617                /* WTF -EIO and not -EFAULT? */
618                return ret ? -EIO : orangefs_bufmap_initialize(&user_desc);
619        case ORANGEFS_DEV_REMOUNT_ALL:
620                gossip_debug(GOSSIP_DEV_DEBUG,
621                             "%s: got ORANGEFS_DEV_REMOUNT_ALL\n",
622                             __func__);
623
624                /*
625                 * remount all mounted orangefs volumes to regain the lost
626                 * dynamic mount tables (if any) -- NOTE: this is done
627                 * without keeping the superblock list locked due to the
628                 * upcall/downcall waiting.  also, the request mutex is
629                 * used to ensure that no operations will be serviced until
630                 * all of the remounts are serviced (to avoid ops between
631                 * mounts to fail)
632                 */
633                ret = mutex_lock_interruptible(&orangefs_request_mutex);
634                if (ret < 0)
635                        return ret;
636                gossip_debug(GOSSIP_DEV_DEBUG,
637                             "%s: priority remount in progress\n",
638                             __func__);
639                spin_lock(&orangefs_superblocks_lock);
640                list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
641                        /*
642                         * We have to drop the spinlock, so entries can be
643                         * removed.  They can't be freed, though, so we just
644                         * keep the forward pointers and zero the back ones -
645                         * that way we can get to the rest of the list.
646                         */
647                        if (!orangefs_sb->list.prev)
648                                continue;
649                        gossip_debug(GOSSIP_DEV_DEBUG,
650                                     "%s: Remounting SB %p\n",
651                                     __func__,
652                                     orangefs_sb);
653
654                        spin_unlock(&orangefs_superblocks_lock);
655                        ret = orangefs_remount(orangefs_sb);
656                        spin_lock(&orangefs_superblocks_lock);
657                        if (ret) {
658                                gossip_debug(GOSSIP_DEV_DEBUG,
659                                             "SB %p remount failed\n",
660                                             orangefs_sb);
661                                break;
662                        }
663                }
664                spin_unlock(&orangefs_superblocks_lock);
665                gossip_debug(GOSSIP_DEV_DEBUG,
666                             "%s: priority remount complete\n",
667                             __func__);
668                mutex_unlock(&orangefs_request_mutex);
669                return ret;
670
671        case ORANGEFS_DEV_UPSTREAM:
672                ret = copy_to_user((void __user *)arg,
673                                    &upstream_kmod,
674                                    sizeof(upstream_kmod));
675
676                if (ret != 0)
677                        return -EIO;
678                else
679                        return ret;
680
681        case ORANGEFS_DEV_CLIENT_MASK:
682                return orangefs_debugfs_new_client_mask((void __user *)arg);
683        case ORANGEFS_DEV_CLIENT_STRING:
684                return orangefs_debugfs_new_client_string((void __user *)arg);
685        case ORANGEFS_DEV_DEBUG:
686                return orangefs_debugfs_new_debug((void __user *)arg);
687        default:
688                return -ENOIOCTLCMD;
689        }
690        return -ENOIOCTLCMD;
691}
692
693static long orangefs_devreq_ioctl(struct file *file,
694                               unsigned int command, unsigned long arg)
695{
696        long ret;
697
698        /* Check for properly constructed commands */
699        ret = check_ioctl_command(command);
700        if (ret < 0)
701                return (int)ret;
702
703        return (int)dispatch_ioctl_command(command, arg);
704}
705
706#ifdef CONFIG_COMPAT            /* CONFIG_COMPAT is in .config */
707
708/*  Compat structure for the ORANGEFS_DEV_MAP ioctl */
709struct ORANGEFS_dev_map_desc32 {
710        compat_uptr_t ptr;
711        __s32 total_size;
712        __s32 size;
713        __s32 count;
714};
715
716static unsigned long translate_dev_map26(unsigned long args, long *error)
717{
718        struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args;
719        /*
720         * Depending on the architecture, allocate some space on the
721         * user-call-stack based on our expected layout.
722         */
723        struct ORANGEFS_dev_map_desc __user *p =
724            compat_alloc_user_space(sizeof(*p));
725        compat_uptr_t addr;
726
727        *error = 0;
728        /* get the ptr from the 32 bit user-space */
729        if (get_user(addr, &p32->ptr))
730                goto err;
731        /* try to put that into a 64-bit layout */
732        if (put_user(compat_ptr(addr), &p->ptr))
733                goto err;
734        /* copy the remaining fields */
735        if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32)))
736                goto err;
737        if (copy_in_user(&p->size, &p32->size, sizeof(__s32)))
738                goto err;
739        if (copy_in_user(&p->count, &p32->count, sizeof(__s32)))
740                goto err;
741        return (unsigned long)p;
742err:
743        *error = -EFAULT;
744        return 0;
745}
746
747/*
748 * 32 bit user-space apps' ioctl handlers when kernel modules
749 * is compiled as a 64 bit one
750 */
751static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd,
752                                      unsigned long args)
753{
754        long ret;
755        unsigned long arg = args;
756
757        /* Check for properly constructed commands */
758        ret = check_ioctl_command(cmd);
759        if (ret < 0)
760                return ret;
761        if (cmd == ORANGEFS_DEV_MAP) {
762                /*
763                 * convert the arguments to what we expect internally
764                 * in kernel space
765                 */
766                arg = translate_dev_map26(args, &ret);
767                if (ret < 0) {
768                        gossip_err("Could not translate dev map\n");
769                        return ret;
770                }
771        }
772        /* no other ioctl requires translation */
773        return dispatch_ioctl_command(cmd, arg);
774}
775
776#endif /* CONFIG_COMPAT is in .config */
777
778/* the assigned character device major number */
779static int orangefs_dev_major;
780
781/*
782 * Initialize orangefs device specific state:
783 * Must be called at module load time only
784 */
785int orangefs_dev_init(void)
786{
787        /* register orangefs-req device  */
788        orangefs_dev_major = register_chrdev(0,
789                                          ORANGEFS_REQDEVICE_NAME,
790                                          &orangefs_devreq_file_operations);
791        if (orangefs_dev_major < 0) {
792                gossip_debug(GOSSIP_DEV_DEBUG,
793                             "Failed to register /dev/%s (error %d)\n",
794                             ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
795                return orangefs_dev_major;
796        }
797
798        gossip_debug(GOSSIP_DEV_DEBUG,
799                     "*** /dev/%s character device registered ***\n",
800                     ORANGEFS_REQDEVICE_NAME);
801        gossip_debug(GOSSIP_DEV_DEBUG, "'mknod /dev/%s c %d 0'.\n",
802                     ORANGEFS_REQDEVICE_NAME, orangefs_dev_major);
803        return 0;
804}
805
806void orangefs_dev_cleanup(void)
807{
808        unregister_chrdev(orangefs_dev_major, ORANGEFS_REQDEVICE_NAME);
809        gossip_debug(GOSSIP_DEV_DEBUG,
810                     "*** /dev/%s character device unregistered ***\n",
811                     ORANGEFS_REQDEVICE_NAME);
812}
813
814static unsigned int orangefs_devreq_poll(struct file *file,
815                                      struct poll_table_struct *poll_table)
816{
817        int poll_revent_mask = 0;
818
819        poll_wait(file, &orangefs_request_list_waitq, poll_table);
820
821        if (!list_empty(&orangefs_request_list))
822                poll_revent_mask |= POLL_IN;
823        return poll_revent_mask;
824}
825
826const struct file_operations orangefs_devreq_file_operations = {
827        .owner = THIS_MODULE,
828        .read = orangefs_devreq_read,
829        .write_iter = orangefs_devreq_write_iter,
830        .open = orangefs_devreq_open,
831        .release = orangefs_devreq_release,
832        .unlocked_ioctl = orangefs_devreq_ioctl,
833
834#ifdef CONFIG_COMPAT            /* CONFIG_COMPAT is in .config */
835        .compat_ioctl = orangefs_devreq_compat_ioctl,
836#endif
837        .poll = orangefs_devreq_poll
838};
Note: See TracBrowser for help on using the repository browser.