aboutsummaryrefslogtreecommitdiffstats
path: root/fs/autofs4/dev-ioctl.c
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2008-10-16 01:02:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 14:21:39 -0400
commit8d7b48e0bc5fa01a818eac713d4cb0763090cd0e (patch)
tree4477b2f23f8596901f38582242a40ff869fb798c /fs/autofs4/dev-ioctl.c
parent4b22ff13415fa30b6282c88da790c82b4c6e5127 (diff)
autofs4: add miscellaneous device for ioctls
Add a miscellaneous device to the autofs4 module for routing ioctls. This provides the ability to obtain an ioctl file handle for an autofs mount point that is possibly covered by another mount. The actual problem with autofs is that it can't reconnect to existing mounts. Immediately one things of just adding the ability to remount autofs file systems would solve it, but alas, that can't work. This is because autofs direct mounts and the implementation of "on demand mount and expire" of nested mount trees have the file system mounted on top of the mount trigger dentry. To resolve this a miscellaneous device node for routing ioctl commands to these mount points has been implemented in the autofs4 kernel module and a library added to autofs. This provides the ability to open a file descriptor for these over mounted autofs mount points. Please refer to Documentation/filesystems/autofs4-mount-control.txt for a discussion of the problem, implementation alternatives considered and a description of the interface. [akpm@linux-foundation.org: coding-style fixes] [akpm@linux-foundation.org: build fix] Signed-off-by: Ian Kent <raven@themaw.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/autofs4/dev-ioctl.c')
-rw-r--r--fs/autofs4/dev-ioctl.c863
1 files changed, 863 insertions, 0 deletions
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
new file mode 100644
index 000000000000..625abf5422e2
--- /dev/null
+++ b/fs/autofs4/dev-ioctl.c
@@ -0,0 +1,863 @@
1/*
2 * Copyright 2008 Red Hat, Inc. All rights reserved.
3 * Copyright 2008 Ian Kent <raven@themaw.net>
4 *
5 * This file is part of the Linux kernel and is made available under
6 * the terms of the GNU General Public License, version 2, or at your
7 * option, any later version, incorporated herein by reference.
8 */
9
10#include <linux/module.h>
11#include <linux/vmalloc.h>
12#include <linux/miscdevice.h>
13#include <linux/init.h>
14#include <linux/wait.h>
15#include <linux/namei.h>
16#include <linux/fcntl.h>
17#include <linux/file.h>
18#include <linux/fdtable.h>
19#include <linux/sched.h>
20#include <linux/compat.h>
21#include <linux/syscalls.h>
22#include <linux/smp_lock.h>
23#include <linux/magic.h>
24#include <linux/dcache.h>
25#include <linux/uaccess.h>
26
27#include "autofs_i.h"
28
29/*
30 * This module implements an interface for routing autofs ioctl control
31 * commands via a miscellaneous device file.
32 *
33 * The alternate interface is needed because we need to be able open
34 * an ioctl file descriptor on an autofs mount that may be covered by
35 * another mount. This situation arises when starting automount(8)
36 * or other user space daemon which uses direct mounts or offset
37 * mounts (used for autofs lazy mount/umount of nested mount trees),
38 * which have been left busy at at service shutdown.
39 */
40
41#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl)
42
43typedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *,
44 struct autofs_dev_ioctl *);
45
46static int check_name(const char *name)
47{
48 if (!strchr(name, '/'))
49 return -EINVAL;
50 return 0;
51}
52
53/*
54 * Check a string doesn't overrun the chunk of
55 * memory we copied from user land.
56 */
57static int invalid_str(char *str, void *end)
58{
59 while ((void *) str <= end)
60 if (!*str++)
61 return 0;
62 return -EINVAL;
63}
64
65/*
66 * Check that the user compiled against correct version of autofs
67 * misc device code.
68 *
69 * As well as checking the version compatibility this always copies
70 * the kernel interface version out.
71 */
72static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param)
73{
74 int err = 0;
75
76 if ((AUTOFS_DEV_IOCTL_VERSION_MAJOR != param->ver_major) ||
77 (AUTOFS_DEV_IOCTL_VERSION_MINOR < param->ver_minor)) {
78 AUTOFS_WARN("ioctl control interface version mismatch: "
79 "kernel(%u.%u), user(%u.%u), cmd(%d)",
80 AUTOFS_DEV_IOCTL_VERSION_MAJOR,
81 AUTOFS_DEV_IOCTL_VERSION_MINOR,
82 param->ver_major, param->ver_minor, cmd);
83 err = -EINVAL;
84 }
85
86 /* Fill in the kernel version. */
87 param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
88 param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
89
90 return err;
91}
92
93/*
94 * Copy parameter control struct, including a possible path allocated
95 * at the end of the struct.
96 */
97static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in)
98{
99 struct autofs_dev_ioctl tmp, *ads;
100
101 if (copy_from_user(&tmp, in, sizeof(tmp)))
102 return ERR_PTR(-EFAULT);
103
104 if (tmp.size < sizeof(tmp))
105 return ERR_PTR(-EINVAL);
106
107 ads = kmalloc(tmp.size, GFP_KERNEL);
108 if (!ads)
109 return ERR_PTR(-ENOMEM);
110
111 if (copy_from_user(ads, in, tmp.size)) {
112 kfree(ads);
113 return ERR_PTR(-EFAULT);
114 }
115
116 return ads;
117}
118
119static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
120{
121 kfree(param);
122 return;
123}
124
125/*
126 * Check sanity of parameter control fields and if a path is present
127 * check that it has a "/" and is terminated.
128 */
129static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
130{
131 int err = -EINVAL;
132
133 if (check_dev_ioctl_version(cmd, param)) {
134 AUTOFS_WARN("invalid device control module version "
135 "supplied for cmd(0x%08x)", cmd);
136 goto out;
137 }
138
139 if (param->size > sizeof(*param)) {
140 err = check_name(param->path);
141 if (err) {
142 AUTOFS_WARN("invalid path supplied for cmd(0x%08x)",
143 cmd);
144 goto out;
145 }
146
147 err = invalid_str(param->path,
148 (void *) ((size_t) param + param->size));
149 if (err) {
150 AUTOFS_WARN("invalid path supplied for cmd(0x%08x)",
151 cmd);
152 goto out;
153 }
154 }
155
156 err = 0;
157out:
158 return err;
159}
160
161/*
162 * Get the autofs super block info struct from the file opened on
163 * the autofs mount point.
164 */
165static struct autofs_sb_info *autofs_dev_ioctl_sbi(struct file *f)
166{
167 struct autofs_sb_info *sbi = NULL;
168 struct inode *inode;
169
170 if (f) {
171 inode = f->f_path.dentry->d_inode;
172 sbi = autofs4_sbi(inode->i_sb);
173 }
174 return sbi;
175}
176
177/* Return autofs module protocol version */
178static int autofs_dev_ioctl_protover(struct file *fp,
179 struct autofs_sb_info *sbi,
180 struct autofs_dev_ioctl *param)
181{
182 param->arg1 = sbi->version;
183 return 0;
184}
185
186/* Return autofs module protocol sub version */
187static int autofs_dev_ioctl_protosubver(struct file *fp,
188 struct autofs_sb_info *sbi,
189 struct autofs_dev_ioctl *param)
190{
191 param->arg1 = sbi->sub_version;
192 return 0;
193}
194
195/*
196 * Walk down the mount stack looking for an autofs mount that
197 * has the requested device number (aka. new_encode_dev(sb->s_dev).
198 */
199static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno)
200{
201 struct dentry *dentry;
202 struct inode *inode;
203 struct super_block *sb;
204 dev_t s_dev;
205 unsigned int err;
206
207 err = -ENOENT;
208
209 /* Lookup the dentry name at the base of our mount point */
210 dentry = d_lookup(nd->path.dentry, &nd->last);
211 if (!dentry)
212 goto out;
213
214 dput(nd->path.dentry);
215 nd->path.dentry = dentry;
216
217 /* And follow the mount stack looking for our autofs mount */
218 while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
219 inode = nd->path.dentry->d_inode;
220 if (!inode)
221 break;
222
223 sb = inode->i_sb;
224 s_dev = new_encode_dev(sb->s_dev);
225 if (devno == s_dev) {
226 if (sb->s_magic == AUTOFS_SUPER_MAGIC) {
227 err = 0;
228 break;
229 }
230 }
231 }
232out:
233 return err;
234}
235
236/*
237 * Walk down the mount stack looking for an autofs mount that
238 * has the requested mount type (ie. indirect, direct or offset).
239 */
240static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type)
241{
242 struct dentry *dentry;
243 struct autofs_info *ino;
244 unsigned int err;
245
246 err = -ENOENT;
247
248 /* Lookup the dentry name at the base of our mount point */
249 dentry = d_lookup(nd->path.dentry, &nd->last);
250 if (!dentry)
251 goto out;
252
253 dput(nd->path.dentry);
254 nd->path.dentry = dentry;
255
256 /* And follow the mount stack looking for our autofs mount */
257 while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
258 ino = autofs4_dentry_ino(nd->path.dentry);
259 if (ino && ino->sbi->type & type) {
260 err = 0;
261 break;
262 }
263 }
264out:
265 return err;
266}
267
268static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file)
269{
270 struct files_struct *files = current->files;
271 struct fdtable *fdt;
272
273 spin_lock(&files->file_lock);
274 fdt = files_fdtable(files);
275 BUG_ON(fdt->fd[fd] != NULL);
276 rcu_assign_pointer(fdt->fd[fd], file);
277 FD_SET(fd, fdt->close_on_exec);
278 spin_unlock(&files->file_lock);
279}
280
281
282/*
283 * Open a file descriptor on the autofs mount point corresponding
284 * to the given path and device number (aka. new_encode_dev(sb->s_dev)).
285 */
286static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid)
287{
288 struct file *filp;
289 struct nameidata nd;
290 int err, fd;
291
292 fd = get_unused_fd();
293 if (likely(fd >= 0)) {
294 /* Get nameidata of the parent directory */
295 err = path_lookup(path, LOOKUP_PARENT, &nd);
296 if (err)
297 goto out;
298
299 /*
300 * Search down, within the parent, looking for an
301 * autofs super block that has the device number
302 * corresponding to the autofs fs we want to open.
303 */
304 err = autofs_dev_ioctl_find_super(&nd, devid);
305 if (err) {
306 path_put(&nd.path);
307 goto out;
308 }
309
310 filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
311 if (IS_ERR(filp)) {
312 err = PTR_ERR(filp);
313 goto out;
314 }
315
316 autofs_dev_ioctl_fd_install(fd, filp);
317 }
318
319 return fd;
320
321out:
322 put_unused_fd(fd);
323 return err;
324}
325
326/* Open a file descriptor on an autofs mount point */
327static int autofs_dev_ioctl_openmount(struct file *fp,
328 struct autofs_sb_info *sbi,
329 struct autofs_dev_ioctl *param)
330{
331 const char *path;
332 dev_t devid;
333 int err, fd;
334
335 /* param->path has already been checked */
336 if (!param->arg1)
337 return -EINVAL;
338
339 param->ioctlfd = -1;
340
341 path = param->path;
342 devid = param->arg1;
343
344 err = 0;
345 fd = autofs_dev_ioctl_open_mountpoint(path, devid);
346 if (unlikely(fd < 0)) {
347 err = fd;
348 goto out;
349 }
350
351 param->ioctlfd = fd;
352out:
353 return err;
354}
355
356/* Close file descriptor allocated above (user can also use close(2)). */
357static int autofs_dev_ioctl_closemount(struct file *fp,
358 struct autofs_sb_info *sbi,
359 struct autofs_dev_ioctl *param)
360{
361 return sys_close(param->ioctlfd);
362}
363
364/*
365 * Send "ready" status for an existing wait (either a mount or an expire
366 * request).
367 */
368static int autofs_dev_ioctl_ready(struct file *fp,
369 struct autofs_sb_info *sbi,
370 struct autofs_dev_ioctl *param)
371{
372 autofs_wqt_t token;
373
374 token = (autofs_wqt_t) param->arg1;
375 return autofs4_wait_release(sbi, token, 0);
376}
377
378/*
379 * Send "fail" status for an existing wait (either a mount or an expire
380 * request).
381 */
382static int autofs_dev_ioctl_fail(struct file *fp,
383 struct autofs_sb_info *sbi,
384 struct autofs_dev_ioctl *param)
385{
386 autofs_wqt_t token;
387 int status;
388
389 token = (autofs_wqt_t) param->arg1;
390 status = param->arg2 ? param->arg2 : -ENOENT;
391 return autofs4_wait_release(sbi, token, status);
392}
393
394/*
395 * Set the pipe fd for kernel communication to the daemon.
396 *
397 * Normally this is set at mount using an option but if we
398 * are reconnecting to a busy mount then we need to use this
399 * to tell the autofs mount about the new kernel pipe fd. In
400 * order to protect mounts against incorrectly setting the
401 * pipefd we also require that the autofs mount be catatonic.
402 *
403 * This also sets the process group id used to identify the
404 * controlling process (eg. the owning automount(8) daemon).
405 */
406static int autofs_dev_ioctl_setpipefd(struct file *fp,
407 struct autofs_sb_info *sbi,
408 struct autofs_dev_ioctl *param)
409{
410 int pipefd;
411 int err = 0;
412
413 if (param->arg1 == -1)
414 return -EINVAL;
415
416 pipefd = param->arg1;
417
418 mutex_lock(&sbi->wq_mutex);
419 if (!sbi->catatonic) {
420 mutex_unlock(&sbi->wq_mutex);
421 return -EBUSY;
422 } else {
423 struct file *pipe = fget(pipefd);
424 if (!pipe->f_op || !pipe->f_op->write) {
425 err = -EPIPE;
426 fput(pipe);
427 goto out;
428 }
429 sbi->oz_pgrp = task_pgrp_nr(current);
430 sbi->pipefd = pipefd;
431 sbi->pipe = pipe;
432 sbi->catatonic = 0;
433 }
434out:
435 mutex_unlock(&sbi->wq_mutex);
436 return err;
437}
438
439/*
440 * Make the autofs mount point catatonic, no longer responsive to
441 * mount requests. Also closes the kernel pipe file descriptor.
442 */
443static int autofs_dev_ioctl_catatonic(struct file *fp,
444 struct autofs_sb_info *sbi,
445 struct autofs_dev_ioctl *param)
446{
447 autofs4_catatonic_mode(sbi);
448 return 0;
449}
450
451/* Set the autofs mount timeout */
452static int autofs_dev_ioctl_timeout(struct file *fp,
453 struct autofs_sb_info *sbi,
454 struct autofs_dev_ioctl *param)
455{
456 unsigned long timeout;
457
458 timeout = param->arg1;
459 param->arg1 = sbi->exp_timeout / HZ;
460 sbi->exp_timeout = timeout * HZ;
461 return 0;
462}
463
464/*
465 * Return the uid and gid of the last request for the mount
466 *
467 * When reconstructing an autofs mount tree with active mounts
468 * we need to re-connect to mounts that may have used the original
469 * process uid and gid (or string variations of them) for mount
470 * lookups within the map entry.
471 */
472static int autofs_dev_ioctl_requester(struct file *fp,
473 struct autofs_sb_info *sbi,
474 struct autofs_dev_ioctl *param)
475{
476 struct autofs_info *ino;
477 struct nameidata nd;
478 const char *path;
479 dev_t devid;
480 int err = -ENOENT;
481
482 if (param->size <= sizeof(*param)) {
483 err = -EINVAL;
484 goto out;
485 }
486
487 path = param->path;
488 devid = sbi->sb->s_dev;
489
490 param->arg1 = param->arg2 = -1;
491
492 /* Get nameidata of the parent directory */
493 err = path_lookup(path, LOOKUP_PARENT, &nd);
494 if (err)
495 goto out;
496
497 err = autofs_dev_ioctl_find_super(&nd, devid);
498 if (err)
499 goto out_release;
500
501 ino = autofs4_dentry_ino(nd.path.dentry);
502 if (ino) {
503 err = 0;
504 autofs4_expire_wait(nd.path.dentry);
505 spin_lock(&sbi->fs_lock);
506 param->arg1 = ino->uid;
507 param->arg2 = ino->gid;
508 spin_unlock(&sbi->fs_lock);
509 }
510
511out_release:
512 path_put(&nd.path);
513out:
514 return err;
515}
516
517/*
518 * Call repeatedly until it returns -EAGAIN, meaning there's nothing
519 * more that can be done.
520 */
521static int autofs_dev_ioctl_expire(struct file *fp,
522 struct autofs_sb_info *sbi,
523 struct autofs_dev_ioctl *param)
524{
525 struct dentry *dentry;
526 struct vfsmount *mnt;
527 int err = -EAGAIN;
528 int how;
529
530 how = param->arg1;
531 mnt = fp->f_path.mnt;
532
533 if (sbi->type & AUTOFS_TYPE_TRIGGER)
534 dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how);
535 else
536 dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how);
537
538 if (dentry) {
539 struct autofs_info *ino = autofs4_dentry_ino(dentry);
540
541 /*
542 * This is synchronous because it makes the daemon a
543 * little easier
544 */
545 err = autofs4_wait(sbi, dentry, NFY_EXPIRE);
546
547 spin_lock(&sbi->fs_lock);
548 if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
549 ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
550 sbi->sb->s_root->d_mounted++;
551 }
552 ino->flags &= ~AUTOFS_INF_EXPIRING;
553 complete_all(&ino->expire_complete);
554 spin_unlock(&sbi->fs_lock);
555 dput(dentry);
556 }
557
558 return err;
559}
560
561/* Check if autofs mount point is in use */
562static int autofs_dev_ioctl_askumount(struct file *fp,
563 struct autofs_sb_info *sbi,
564 struct autofs_dev_ioctl *param)
565{
566 param->arg1 = 0;
567 if (may_umount(fp->f_path.mnt))
568 param->arg1 = 1;
569 return 0;
570}
571
572/*
573 * Check if the given path is a mountpoint.
574 *
575 * If we are supplied with the file descriptor of an autofs
576 * mount we're looking for a specific mount. In this case
577 * the path is considered a mountpoint if it is itself a
578 * mountpoint or contains a mount, such as a multi-mount
579 * without a root mount. In this case we return 1 if the
580 * path is a mount point and the super magic of the covering
581 * mount if there is one or 0 if it isn't a mountpoint.
582 *
583 * If we aren't supplied with a file descriptor then we
584 * lookup the nameidata of the path and check if it is the
585 * root of a mount. If a type is given we are looking for
586 * a particular autofs mount and if we don't find a match
587 * we return fail. If the located nameidata path is the
588 * root of a mount we return 1 along with the super magic
589 * of the mount or 0 otherwise.
590 *
591 * In both cases the the device number (as returned by
592 * new_encode_dev()) is also returned.
593 */
594static int autofs_dev_ioctl_ismountpoint(struct file *fp,
595 struct autofs_sb_info *sbi,
596 struct autofs_dev_ioctl *param)
597{
598 struct nameidata nd;
599 const char *path;
600 unsigned int type;
601 int err = -ENOENT;
602
603 if (param->size <= sizeof(*param)) {
604 err = -EINVAL;
605 goto out;
606 }
607
608 path = param->path;
609 type = param->arg1;
610
611 param->arg1 = 0;
612 param->arg2 = 0;
613
614 if (!fp || param->ioctlfd == -1) {
615 if (type == AUTOFS_TYPE_ANY) {
616 struct super_block *sb;
617
618 err = path_lookup(path, LOOKUP_FOLLOW, &nd);
619 if (err)
620 goto out;
621
622 sb = nd.path.dentry->d_sb;
623 param->arg1 = new_encode_dev(sb->s_dev);
624 } else {
625 struct autofs_info *ino;
626
627 err = path_lookup(path, LOOKUP_PARENT, &nd);
628 if (err)
629 goto out;
630
631 err = autofs_dev_ioctl_find_sbi_type(&nd, type);
632 if (err)
633 goto out_release;
634
635 ino = autofs4_dentry_ino(nd.path.dentry);
636 param->arg1 = autofs4_get_dev(ino->sbi);
637 }
638
639 err = 0;
640 if (nd.path.dentry->d_inode &&
641 nd.path.mnt->mnt_root == nd.path.dentry) {
642 err = 1;
643 param->arg2 = nd.path.dentry->d_inode->i_sb->s_magic;
644 }
645 } else {
646 dev_t devid = new_encode_dev(sbi->sb->s_dev);
647
648 err = path_lookup(path, LOOKUP_PARENT, &nd);
649 if (err)
650 goto out;
651
652 err = autofs_dev_ioctl_find_super(&nd, devid);
653 if (err)
654 goto out_release;
655
656 param->arg1 = autofs4_get_dev(sbi);
657
658 err = have_submounts(nd.path.dentry);
659
660 if (nd.path.mnt->mnt_mountpoint != nd.path.mnt->mnt_root) {
661 if (follow_down(&nd.path.mnt, &nd.path.dentry)) {
662 struct inode *inode = nd.path.dentry->d_inode;
663 param->arg2 = inode->i_sb->s_magic;
664 }
665 }
666 }
667
668out_release:
669 path_put(&nd.path);
670out:
671 return err;
672}
673
674/*
675 * Our range of ioctl numbers isn't 0 based so we need to shift
676 * the array index by _IOC_NR(AUTOFS_CTL_IOC_FIRST) for the table
677 * lookup.
678 */
679#define cmd_idx(cmd) (cmd - _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST))
680
681static ioctl_fn lookup_dev_ioctl(unsigned int cmd)
682{
683 static struct {
684 int cmd;
685 ioctl_fn fn;
686 } _ioctls[] = {
687 {cmd_idx(AUTOFS_DEV_IOCTL_VERSION_CMD), NULL},
688 {cmd_idx(AUTOFS_DEV_IOCTL_PROTOVER_CMD),
689 autofs_dev_ioctl_protover},
690 {cmd_idx(AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD),
691 autofs_dev_ioctl_protosubver},
692 {cmd_idx(AUTOFS_DEV_IOCTL_OPENMOUNT_CMD),
693 autofs_dev_ioctl_openmount},
694 {cmd_idx(AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD),
695 autofs_dev_ioctl_closemount},
696 {cmd_idx(AUTOFS_DEV_IOCTL_READY_CMD),
697 autofs_dev_ioctl_ready},
698 {cmd_idx(AUTOFS_DEV_IOCTL_FAIL_CMD),
699 autofs_dev_ioctl_fail},
700 {cmd_idx(AUTOFS_DEV_IOCTL_SETPIPEFD_CMD),
701 autofs_dev_ioctl_setpipefd},
702 {cmd_idx(AUTOFS_DEV_IOCTL_CATATONIC_CMD),
703 autofs_dev_ioctl_catatonic},
704 {cmd_idx(AUTOFS_DEV_IOCTL_TIMEOUT_CMD),
705 autofs_dev_ioctl_timeout},
706 {cmd_idx(AUTOFS_DEV_IOCTL_REQUESTER_CMD),
707 autofs_dev_ioctl_requester},
708 {cmd_idx(AUTOFS_DEV_IOCTL_EXPIRE_CMD),
709 autofs_dev_ioctl_expire},
710 {cmd_idx(AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD),
711 autofs_dev_ioctl_askumount},
712 {cmd_idx(AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD),
713 autofs_dev_ioctl_ismountpoint}
714 };
715 unsigned int idx = cmd_idx(cmd);
716
717 return (idx >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[idx].fn;
718}
719
720/* ioctl dispatcher */
721static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user)
722{
723 struct autofs_dev_ioctl *param;
724 struct file *fp;
725 struct autofs_sb_info *sbi;
726 unsigned int cmd_first, cmd;
727 ioctl_fn fn = NULL;
728 int err = 0;
729
730 /* only root can play with this */
731 if (!capable(CAP_SYS_ADMIN))
732 return -EPERM;
733
734 cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST);
735 cmd = _IOC_NR(command);
736
737 if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) ||
738 cmd - cmd_first >= AUTOFS_DEV_IOCTL_IOC_COUNT) {
739 return -ENOTTY;
740 }
741
742 /* Copy the parameters into kernel space. */
743 param = copy_dev_ioctl(user);
744 if (IS_ERR(param))
745 return PTR_ERR(param);
746
747 err = validate_dev_ioctl(command, param);
748 if (err)
749 goto out;
750
751 /* The validate routine above always sets the version */
752 if (cmd == AUTOFS_DEV_IOCTL_VERSION_CMD)
753 goto done;
754
755 fn = lookup_dev_ioctl(cmd);
756 if (!fn) {
757 AUTOFS_WARN("unknown command 0x%08x", command);
758 return -ENOTTY;
759 }
760
761 fp = NULL;
762 sbi = NULL;
763
764 /*
765 * For obvious reasons the openmount can't have a file
766 * descriptor yet. We don't take a reference to the
767 * file during close to allow for immediate release.
768 */
769 if (cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD &&
770 cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) {
771 fp = fget(param->ioctlfd);
772 if (!fp) {
773 if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD)
774 goto cont;
775 err = -EBADF;
776 goto out;
777 }
778
779 if (!fp->f_op) {
780 err = -ENOTTY;
781 fput(fp);
782 goto out;
783 }
784
785 sbi = autofs_dev_ioctl_sbi(fp);
786 if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) {
787 err = -EINVAL;
788 fput(fp);
789 goto out;
790 }
791
792 /*
793 * Admin needs to be able to set the mount catatonic in
794 * order to be able to perform the re-open.
795 */
796 if (!autofs4_oz_mode(sbi) &&
797 cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) {
798 err = -EACCES;
799 fput(fp);
800 goto out;
801 }
802 }
803cont:
804 err = fn(fp, sbi, param);
805
806 if (fp)
807 fput(fp);
808done:
809 if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE))
810 err = -EFAULT;
811out:
812 free_dev_ioctl(param);
813 return err;
814}
815
816static long autofs_dev_ioctl(struct file *file, uint command, ulong u)
817{
818 int err;
819 err = _autofs_dev_ioctl(command, (struct autofs_dev_ioctl __user *) u);
820 return (long) err;
821}
822
823#ifdef CONFIG_COMPAT
824static long autofs_dev_ioctl_compat(struct file *file, uint command, ulong u)
825{
826 return (long) autofs_dev_ioctl(file, command, (ulong) compat_ptr(u));
827}
828#else
829#define autofs_dev_ioctl_compat NULL
830#endif
831
832static const struct file_operations _dev_ioctl_fops = {
833 .unlocked_ioctl = autofs_dev_ioctl,
834 .compat_ioctl = autofs_dev_ioctl_compat,
835 .owner = THIS_MODULE,
836};
837
838static struct miscdevice _autofs_dev_ioctl_misc = {
839 .minor = MISC_DYNAMIC_MINOR,
840 .name = AUTOFS_DEVICE_NAME,
841 .fops = &_dev_ioctl_fops
842};
843
844/* Register/deregister misc character device */
845int autofs_dev_ioctl_init(void)
846{
847 int r;
848
849 r = misc_register(&_autofs_dev_ioctl_misc);
850 if (r) {
851 AUTOFS_ERROR("misc_register failed for control device");
852 return r;
853 }
854
855 return 0;
856}
857
858void autofs_dev_ioctl_exit(void)
859{
860 misc_deregister(&_autofs_dev_ioctl_misc);
861 return;
862}
863