diff options
Diffstat (limited to 'fs/autofs/root.c')
-rw-r--r-- | fs/autofs/root.c | 643 |
1 files changed, 0 insertions, 643 deletions
diff --git a/fs/autofs/root.c b/fs/autofs/root.c deleted file mode 100644 index 11b1ea786d00..000000000000 --- a/fs/autofs/root.c +++ /dev/null | |||
@@ -1,643 +0,0 @@ | |||
1 | /* -*- linux-c -*- --------------------------------------------------------- * | ||
2 | * | ||
3 | * linux/fs/autofs/root.c | ||
4 | * | ||
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | ||
6 | * | ||
7 | * This file is part of the Linux kernel and is made available under | ||
8 | * the terms of the GNU General Public License, version 2, or at your | ||
9 | * option, any later version, incorporated herein by reference. | ||
10 | * | ||
11 | * ------------------------------------------------------------------------- */ | ||
12 | |||
13 | #include <linux/capability.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/stat.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/param.h> | ||
18 | #include <linux/time.h> | ||
19 | #include <linux/compat.h> | ||
20 | #include <linux/smp_lock.h> | ||
21 | #include "autofs_i.h" | ||
22 | |||
23 | static int autofs_root_readdir(struct file *,void *,filldir_t); | ||
24 | static struct dentry *autofs_root_lookup(struct inode *,struct dentry *, struct nameidata *); | ||
25 | static int autofs_root_symlink(struct inode *,struct dentry *,const char *); | ||
26 | static int autofs_root_unlink(struct inode *,struct dentry *); | ||
27 | static int autofs_root_rmdir(struct inode *,struct dentry *); | ||
28 | static int autofs_root_mkdir(struct inode *,struct dentry *,int); | ||
29 | static long autofs_root_ioctl(struct file *,unsigned int,unsigned long); | ||
30 | static long autofs_root_compat_ioctl(struct file *,unsigned int,unsigned long); | ||
31 | |||
32 | const struct file_operations autofs_root_operations = { | ||
33 | .llseek = generic_file_llseek, | ||
34 | .read = generic_read_dir, | ||
35 | .readdir = autofs_root_readdir, | ||
36 | .unlocked_ioctl = autofs_root_ioctl, | ||
37 | #ifdef CONFIG_COMPAT | ||
38 | .compat_ioctl = autofs_root_compat_ioctl, | ||
39 | #endif | ||
40 | }; | ||
41 | |||
42 | const struct inode_operations autofs_root_inode_operations = { | ||
43 | .lookup = autofs_root_lookup, | ||
44 | .unlink = autofs_root_unlink, | ||
45 | .symlink = autofs_root_symlink, | ||
46 | .mkdir = autofs_root_mkdir, | ||
47 | .rmdir = autofs_root_rmdir, | ||
48 | }; | ||
49 | |||
50 | static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
51 | { | ||
52 | struct autofs_dir_ent *ent = NULL; | ||
53 | struct autofs_dirhash *dirhash; | ||
54 | struct autofs_sb_info *sbi; | ||
55 | struct inode * inode = filp->f_path.dentry->d_inode; | ||
56 | off_t onr, nr; | ||
57 | |||
58 | lock_kernel(); | ||
59 | |||
60 | sbi = autofs_sbi(inode->i_sb); | ||
61 | dirhash = &sbi->dirhash; | ||
62 | nr = filp->f_pos; | ||
63 | |||
64 | switch(nr) | ||
65 | { | ||
66 | case 0: | ||
67 | if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) | ||
68 | goto out; | ||
69 | filp->f_pos = ++nr; | ||
70 | /* fall through */ | ||
71 | case 1: | ||
72 | if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) | ||
73 | goto out; | ||
74 | filp->f_pos = ++nr; | ||
75 | /* fall through */ | ||
76 | default: | ||
77 | while (onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent)) { | ||
78 | if (!ent->dentry || d_mountpoint(ent->dentry)) { | ||
79 | if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0) | ||
80 | goto out; | ||
81 | filp->f_pos = nr; | ||
82 | } | ||
83 | } | ||
84 | break; | ||
85 | } | ||
86 | |||
87 | out: | ||
88 | unlock_kernel(); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, struct autofs_sb_info *sbi) | ||
93 | { | ||
94 | struct inode * inode; | ||
95 | struct autofs_dir_ent *ent; | ||
96 | int status = 0; | ||
97 | |||
98 | if (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) { | ||
99 | do { | ||
100 | if (status && dentry->d_inode) { | ||
101 | if (status != -ENOENT) | ||
102 | printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name); | ||
103 | return 0; /* Try to get the kernel to invalidate this dentry */ | ||
104 | } | ||
105 | |||
106 | /* Turn this into a real negative dentry? */ | ||
107 | if (status == -ENOENT) { | ||
108 | dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT; | ||
109 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | ||
110 | return 1; | ||
111 | } else if (status) { | ||
112 | /* Return a negative dentry, but leave it "pending" */ | ||
113 | return 1; | ||
114 | } | ||
115 | status = autofs_wait(sbi, &dentry->d_name); | ||
116 | } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))); | ||
117 | } | ||
118 | |||
119 | /* Abuse this field as a pointer to the directory entry, used to | ||
120 | find the expire list pointers */ | ||
121 | dentry->d_time = (unsigned long) ent; | ||
122 | |||
123 | if (!dentry->d_inode) { | ||
124 | inode = autofs_iget(sb, ent->ino); | ||
125 | if (IS_ERR(inode)) { | ||
126 | /* Failed, but leave pending for next time */ | ||
127 | return 1; | ||
128 | } | ||
129 | dentry->d_inode = inode; | ||
130 | } | ||
131 | |||
132 | /* If this is a directory that isn't a mount point, bitch at the | ||
133 | daemon and fix it in user space */ | ||
134 | if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) { | ||
135 | return !autofs_wait(sbi, &dentry->d_name); | ||
136 | } | ||
137 | |||
138 | /* We don't update the usages for the autofs daemon itself, this | ||
139 | is necessary for recursive autofs mounts */ | ||
140 | if (!autofs_oz_mode(sbi)) { | ||
141 | autofs_update_usage(&sbi->dirhash,ent); | ||
142 | } | ||
143 | |||
144 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | ||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | |||
149 | /* | ||
150 | * Revalidate is called on every cache lookup. Some of those | ||
151 | * cache lookups may actually happen while the dentry is not | ||
152 | * yet completely filled in, and revalidate has to delay such | ||
153 | * lookups.. | ||
154 | */ | ||
155 | static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) | ||
156 | { | ||
157 | struct inode * dir; | ||
158 | struct autofs_sb_info *sbi; | ||
159 | struct autofs_dir_ent *ent; | ||
160 | int res; | ||
161 | |||
162 | lock_kernel(); | ||
163 | dir = dentry->d_parent->d_inode; | ||
164 | sbi = autofs_sbi(dir->i_sb); | ||
165 | |||
166 | /* Pending dentry */ | ||
167 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { | ||
168 | if (autofs_oz_mode(sbi)) | ||
169 | res = 1; | ||
170 | else | ||
171 | res = try_to_fill_dentry(dentry, dir->i_sb, sbi); | ||
172 | unlock_kernel(); | ||
173 | return res; | ||
174 | } | ||
175 | |||
176 | /* Negative dentry.. invalidate if "old" */ | ||
177 | if (!dentry->d_inode) { | ||
178 | unlock_kernel(); | ||
179 | return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT); | ||
180 | } | ||
181 | |||
182 | /* Check for a non-mountpoint directory */ | ||
183 | if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) { | ||
184 | if (autofs_oz_mode(sbi)) | ||
185 | res = 1; | ||
186 | else | ||
187 | res = try_to_fill_dentry(dentry, dir->i_sb, sbi); | ||
188 | unlock_kernel(); | ||
189 | return res; | ||
190 | } | ||
191 | |||
192 | /* Update the usage list */ | ||
193 | if (!autofs_oz_mode(sbi)) { | ||
194 | ent = (struct autofs_dir_ent *) dentry->d_time; | ||
195 | if (ent) | ||
196 | autofs_update_usage(&sbi->dirhash,ent); | ||
197 | } | ||
198 | unlock_kernel(); | ||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | static const struct dentry_operations autofs_dentry_operations = { | ||
203 | .d_revalidate = autofs_revalidate, | ||
204 | }; | ||
205 | |||
206 | static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
207 | { | ||
208 | struct autofs_sb_info *sbi; | ||
209 | int oz_mode; | ||
210 | |||
211 | DPRINTK(("autofs_root_lookup: name = ")); | ||
212 | lock_kernel(); | ||
213 | autofs_say(dentry->d_name.name,dentry->d_name.len); | ||
214 | |||
215 | if (dentry->d_name.len > NAME_MAX) { | ||
216 | unlock_kernel(); | ||
217 | return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */ | ||
218 | } | ||
219 | |||
220 | sbi = autofs_sbi(dir->i_sb); | ||
221 | |||
222 | oz_mode = autofs_oz_mode(sbi); | ||
223 | DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, " | ||
224 | "oz_mode = %d\n", task_pid_nr(current), | ||
225 | task_pgrp_nr(current), sbi->catatonic, | ||
226 | oz_mode)); | ||
227 | |||
228 | /* | ||
229 | * Mark the dentry incomplete, but add it. This is needed so | ||
230 | * that the VFS layer knows about the dentry, and we can count | ||
231 | * on catching any lookups through the revalidate. | ||
232 | * | ||
233 | * Let all the hard work be done by the revalidate function that | ||
234 | * needs to be able to do this anyway.. | ||
235 | * | ||
236 | * We need to do this before we release the directory semaphore. | ||
237 | */ | ||
238 | dentry->d_op = &autofs_dentry_operations; | ||
239 | dentry->d_flags |= DCACHE_AUTOFS_PENDING; | ||
240 | d_add(dentry, NULL); | ||
241 | |||
242 | mutex_unlock(&dir->i_mutex); | ||
243 | autofs_revalidate(dentry, nd); | ||
244 | mutex_lock(&dir->i_mutex); | ||
245 | |||
246 | /* | ||
247 | * If we are still pending, check if we had to handle | ||
248 | * a signal. If so we can force a restart.. | ||
249 | */ | ||
250 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { | ||
251 | /* See if we were interrupted */ | ||
252 | if (signal_pending(current)) { | ||
253 | sigset_t *sigset = ¤t->pending.signal; | ||
254 | if (sigismember (sigset, SIGKILL) || | ||
255 | sigismember (sigset, SIGQUIT) || | ||
256 | sigismember (sigset, SIGINT)) { | ||
257 | unlock_kernel(); | ||
258 | return ERR_PTR(-ERESTARTNOINTR); | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | unlock_kernel(); | ||
263 | |||
264 | /* | ||
265 | * If this dentry is unhashed, then we shouldn't honour this | ||
266 | * lookup even if the dentry is positive. Returning ENOENT here | ||
267 | * doesn't do the right thing for all system calls, but it should | ||
268 | * be OK for the operations we permit from an autofs. | ||
269 | */ | ||
270 | if (dentry->d_inode && d_unhashed(dentry)) | ||
271 | return ERR_PTR(-ENOENT); | ||
272 | |||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | ||
277 | { | ||
278 | struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); | ||
279 | struct autofs_dirhash *dh = &sbi->dirhash; | ||
280 | struct autofs_dir_ent *ent; | ||
281 | unsigned int n; | ||
282 | int slsize; | ||
283 | struct autofs_symlink *sl; | ||
284 | struct inode *inode; | ||
285 | |||
286 | DPRINTK(("autofs_root_symlink: %s <- ", symname)); | ||
287 | autofs_say(dentry->d_name.name,dentry->d_name.len); | ||
288 | |||
289 | lock_kernel(); | ||
290 | if (!autofs_oz_mode(sbi)) { | ||
291 | unlock_kernel(); | ||
292 | return -EACCES; | ||
293 | } | ||
294 | |||
295 | if (autofs_hash_lookup(dh, &dentry->d_name)) { | ||
296 | unlock_kernel(); | ||
297 | return -EEXIST; | ||
298 | } | ||
299 | |||
300 | n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS); | ||
301 | if (n >= AUTOFS_MAX_SYMLINKS) { | ||
302 | unlock_kernel(); | ||
303 | return -ENOSPC; | ||
304 | } | ||
305 | |||
306 | set_bit(n,sbi->symlink_bitmap); | ||
307 | sl = &sbi->symlink[n]; | ||
308 | sl->len = strlen(symname); | ||
309 | sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL); | ||
310 | if (!sl->data) { | ||
311 | clear_bit(n,sbi->symlink_bitmap); | ||
312 | unlock_kernel(); | ||
313 | return -ENOSPC; | ||
314 | } | ||
315 | |||
316 | ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); | ||
317 | if (!ent) { | ||
318 | kfree(sl->data); | ||
319 | clear_bit(n,sbi->symlink_bitmap); | ||
320 | unlock_kernel(); | ||
321 | return -ENOSPC; | ||
322 | } | ||
323 | |||
324 | ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL); | ||
325 | if (!ent->name) { | ||
326 | kfree(sl->data); | ||
327 | kfree(ent); | ||
328 | clear_bit(n,sbi->symlink_bitmap); | ||
329 | unlock_kernel(); | ||
330 | return -ENOSPC; | ||
331 | } | ||
332 | |||
333 | memcpy(sl->data,symname,slsize); | ||
334 | sl->mtime = get_seconds(); | ||
335 | |||
336 | ent->ino = AUTOFS_FIRST_SYMLINK + n; | ||
337 | ent->hash = dentry->d_name.hash; | ||
338 | memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len)); | ||
339 | ent->dentry = NULL; /* We don't keep the dentry for symlinks */ | ||
340 | |||
341 | autofs_hash_insert(dh,ent); | ||
342 | |||
343 | inode = autofs_iget(dir->i_sb, ent->ino); | ||
344 | if (IS_ERR(inode)) | ||
345 | return PTR_ERR(inode); | ||
346 | |||
347 | d_instantiate(dentry, inode); | ||
348 | unlock_kernel(); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * NOTE! | ||
354 | * | ||
355 | * Normal filesystems would do a "d_delete()" to tell the VFS dcache | ||
356 | * that the file no longer exists. However, doing that means that the | ||
357 | * VFS layer can turn the dentry into a negative dentry, which we | ||
358 | * obviously do not want (we're dropping the entry not because it | ||
359 | * doesn't exist, but because it has timed out). | ||
360 | * | ||
361 | * Also see autofs_root_rmdir().. | ||
362 | */ | ||
363 | static int autofs_root_unlink(struct inode *dir, struct dentry *dentry) | ||
364 | { | ||
365 | struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); | ||
366 | struct autofs_dirhash *dh = &sbi->dirhash; | ||
367 | struct autofs_dir_ent *ent; | ||
368 | unsigned int n; | ||
369 | |||
370 | /* This allows root to remove symlinks */ | ||
371 | lock_kernel(); | ||
372 | if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) { | ||
373 | unlock_kernel(); | ||
374 | return -EACCES; | ||
375 | } | ||
376 | |||
377 | ent = autofs_hash_lookup(dh, &dentry->d_name); | ||
378 | if (!ent) { | ||
379 | unlock_kernel(); | ||
380 | return -ENOENT; | ||
381 | } | ||
382 | |||
383 | n = ent->ino - AUTOFS_FIRST_SYMLINK; | ||
384 | if (n >= AUTOFS_MAX_SYMLINKS) { | ||
385 | unlock_kernel(); | ||
386 | return -EISDIR; /* It's a directory, dummy */ | ||
387 | } | ||
388 | if (!test_bit(n,sbi->symlink_bitmap)) { | ||
389 | unlock_kernel(); | ||
390 | return -EINVAL; /* Nonexistent symlink? Shouldn't happen */ | ||
391 | } | ||
392 | |||
393 | dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL; | ||
394 | autofs_hash_delete(ent); | ||
395 | clear_bit(n,sbi->symlink_bitmap); | ||
396 | kfree(sbi->symlink[n].data); | ||
397 | d_drop(dentry); | ||
398 | |||
399 | unlock_kernel(); | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry) | ||
404 | { | ||
405 | struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); | ||
406 | struct autofs_dirhash *dh = &sbi->dirhash; | ||
407 | struct autofs_dir_ent *ent; | ||
408 | |||
409 | lock_kernel(); | ||
410 | if (!autofs_oz_mode(sbi)) { | ||
411 | unlock_kernel(); | ||
412 | return -EACCES; | ||
413 | } | ||
414 | |||
415 | ent = autofs_hash_lookup(dh, &dentry->d_name); | ||
416 | if (!ent) { | ||
417 | unlock_kernel(); | ||
418 | return -ENOENT; | ||
419 | } | ||
420 | |||
421 | if ((unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO) { | ||
422 | unlock_kernel(); | ||
423 | return -ENOTDIR; /* Not a directory */ | ||
424 | } | ||
425 | |||
426 | if (ent->dentry != dentry) { | ||
427 | printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name); | ||
428 | } | ||
429 | |||
430 | dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL; | ||
431 | autofs_hash_delete(ent); | ||
432 | drop_nlink(dir); | ||
433 | d_drop(dentry); | ||
434 | unlock_kernel(); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
440 | { | ||
441 | struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb); | ||
442 | struct autofs_dirhash *dh = &sbi->dirhash; | ||
443 | struct autofs_dir_ent *ent; | ||
444 | struct inode *inode; | ||
445 | ino_t ino; | ||
446 | |||
447 | lock_kernel(); | ||
448 | if (!autofs_oz_mode(sbi)) { | ||
449 | unlock_kernel(); | ||
450 | return -EACCES; | ||
451 | } | ||
452 | |||
453 | ent = autofs_hash_lookup(dh, &dentry->d_name); | ||
454 | if (ent) { | ||
455 | unlock_kernel(); | ||
456 | return -EEXIST; | ||
457 | } | ||
458 | |||
459 | if (sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO) { | ||
460 | printk("autofs: Out of inode numbers -- what the heck did you do??\n"); | ||
461 | unlock_kernel(); | ||
462 | return -ENOSPC; | ||
463 | } | ||
464 | ino = sbi->next_dir_ino++; | ||
465 | |||
466 | ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); | ||
467 | if (!ent) { | ||
468 | unlock_kernel(); | ||
469 | return -ENOSPC; | ||
470 | } | ||
471 | |||
472 | ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL); | ||
473 | if (!ent->name) { | ||
474 | kfree(ent); | ||
475 | unlock_kernel(); | ||
476 | return -ENOSPC; | ||
477 | } | ||
478 | |||
479 | ent->hash = dentry->d_name.hash; | ||
480 | memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len)); | ||
481 | ent->ino = ino; | ||
482 | ent->dentry = dentry; | ||
483 | autofs_hash_insert(dh,ent); | ||
484 | |||
485 | inc_nlink(dir); | ||
486 | |||
487 | inode = autofs_iget(dir->i_sb, ino); | ||
488 | if (IS_ERR(inode)) { | ||
489 | drop_nlink(dir); | ||
490 | return PTR_ERR(inode); | ||
491 | } | ||
492 | |||
493 | d_instantiate(dentry, inode); | ||
494 | unlock_kernel(); | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | /* Get/set timeout ioctl() operation */ | ||
500 | #ifdef CONFIG_COMPAT | ||
501 | static inline int autofs_compat_get_set_timeout(struct autofs_sb_info *sbi, | ||
502 | unsigned int __user *p) | ||
503 | { | ||
504 | unsigned long ntimeout; | ||
505 | |||
506 | if (get_user(ntimeout, p) || | ||
507 | put_user(sbi->exp_timeout / HZ, p)) | ||
508 | return -EFAULT; | ||
509 | |||
510 | if (ntimeout > UINT_MAX/HZ) | ||
511 | sbi->exp_timeout = 0; | ||
512 | else | ||
513 | sbi->exp_timeout = ntimeout * HZ; | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | #endif | ||
518 | |||
519 | static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi, | ||
520 | unsigned long __user *p) | ||
521 | { | ||
522 | unsigned long ntimeout; | ||
523 | |||
524 | if (get_user(ntimeout, p) || | ||
525 | put_user(sbi->exp_timeout / HZ, p)) | ||
526 | return -EFAULT; | ||
527 | |||
528 | if (ntimeout > ULONG_MAX/HZ) | ||
529 | sbi->exp_timeout = 0; | ||
530 | else | ||
531 | sbi->exp_timeout = ntimeout * HZ; | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | /* Return protocol version */ | ||
537 | static inline int autofs_get_protover(int __user *p) | ||
538 | { | ||
539 | return put_user(AUTOFS_PROTO_VERSION, p); | ||
540 | } | ||
541 | |||
542 | /* Perform an expiry operation */ | ||
543 | static inline int autofs_expire_run(struct super_block *sb, | ||
544 | struct autofs_sb_info *sbi, | ||
545 | struct vfsmount *mnt, | ||
546 | struct autofs_packet_expire __user *pkt_p) | ||
547 | { | ||
548 | struct autofs_dir_ent *ent; | ||
549 | struct autofs_packet_expire pkt; | ||
550 | |||
551 | memset(&pkt,0,sizeof pkt); | ||
552 | |||
553 | pkt.hdr.proto_version = AUTOFS_PROTO_VERSION; | ||
554 | pkt.hdr.type = autofs_ptype_expire; | ||
555 | |||
556 | if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt))) | ||
557 | return -EAGAIN; | ||
558 | |||
559 | pkt.len = ent->len; | ||
560 | memcpy(pkt.name, ent->name, pkt.len); | ||
561 | pkt.name[pkt.len] = '\0'; | ||
562 | |||
563 | if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire))) | ||
564 | return -EFAULT; | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | /* | ||
570 | * ioctl()'s on the root directory is the chief method for the daemon to | ||
571 | * generate kernel reactions | ||
572 | */ | ||
573 | static int autofs_do_root_ioctl(struct inode *inode, struct file *filp, | ||
574 | unsigned int cmd, unsigned long arg) | ||
575 | { | ||
576 | struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb); | ||
577 | void __user *argp = (void __user *)arg; | ||
578 | |||
579 | DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,task_pgrp_nr(current))); | ||
580 | |||
581 | if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || | ||
582 | _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) | ||
583 | return -ENOTTY; | ||
584 | |||
585 | if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) | ||
586 | return -EPERM; | ||
587 | |||
588 | switch(cmd) { | ||
589 | case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */ | ||
590 | return autofs_wait_release(sbi,(autofs_wqt_t)arg,0); | ||
591 | case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */ | ||
592 | return autofs_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT); | ||
593 | case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */ | ||
594 | autofs_catatonic_mode(sbi); | ||
595 | return 0; | ||
596 | case AUTOFS_IOC_PROTOVER: /* Get protocol version */ | ||
597 | return autofs_get_protover(argp); | ||
598 | #ifdef CONFIG_COMPAT | ||
599 | case AUTOFS_IOC_SETTIMEOUT32: | ||
600 | return autofs_compat_get_set_timeout(sbi, argp); | ||
601 | #endif | ||
602 | case AUTOFS_IOC_SETTIMEOUT: | ||
603 | return autofs_get_set_timeout(sbi, argp); | ||
604 | case AUTOFS_IOC_EXPIRE: | ||
605 | return autofs_expire_run(inode->i_sb, sbi, filp->f_path.mnt, | ||
606 | argp); | ||
607 | default: | ||
608 | return -ENOSYS; | ||
609 | } | ||
610 | |||
611 | } | ||
612 | |||
613 | static long autofs_root_ioctl(struct file *filp, | ||
614 | unsigned int cmd, unsigned long arg) | ||
615 | { | ||
616 | int ret; | ||
617 | |||
618 | lock_kernel(); | ||
619 | ret = autofs_do_root_ioctl(filp->f_path.dentry->d_inode, | ||
620 | filp, cmd, arg); | ||
621 | unlock_kernel(); | ||
622 | |||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | #ifdef CONFIG_COMPAT | ||
627 | static long autofs_root_compat_ioctl(struct file *filp, | ||
628 | unsigned int cmd, unsigned long arg) | ||
629 | { | ||
630 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
631 | int ret; | ||
632 | |||
633 | lock_kernel(); | ||
634 | if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) | ||
635 | ret = autofs_do_root_ioctl(inode, filp, cmd, arg); | ||
636 | else | ||
637 | ret = autofs_do_root_ioctl(inode, filp, cmd, | ||
638 | (unsigned long)compat_ptr(arg)); | ||
639 | unlock_kernel(); | ||
640 | |||
641 | return ret; | ||
642 | } | ||
643 | #endif | ||