Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
4 : : * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
5 : : * Copyright 2001-2006 Ian Kent <raven@themaw.net>
6 : : */
7 : :
8 : : #include "autofs_i.h"
9 : :
10 : : /* Check if a dentry can be expired */
11 : : static inline int autofs_can_expire(struct dentry *dentry,
12 : : unsigned long timeout, unsigned int how)
13 : : {
14 : : struct autofs_info *ino = autofs_dentry_ino(dentry);
15 : :
16 : : /* dentry in the process of being deleted */
17 [ # # # # : 0 : if (ino == NULL)
# # # # #
# ]
18 : : return 0;
19 : :
20 [ # # # # : 0 : if (!(how & AUTOFS_EXP_IMMEDIATE)) {
# # # # #
# ]
21 : : /* Too young to die */
22 [ # # # # : 0 : if (!timeout || time_after(ino->last_used + timeout, jiffies))
# # # # #
# # # # #
# # # # #
# ]
23 : : return 0;
24 : : }
25 : : return 1;
26 : : }
27 : :
28 : : /* Check a mount point for busyness */
29 : 0 : static int autofs_mount_busy(struct vfsmount *mnt,
30 : : struct dentry *dentry, unsigned int how)
31 : : {
32 : : struct dentry *top = dentry;
33 : 0 : struct path path = {.mnt = mnt, .dentry = dentry};
34 : : int status = 1;
35 : :
36 : : pr_debug("dentry %p %pd\n", dentry, dentry);
37 : :
38 : 0 : path_get(&path);
39 : :
40 [ # # ]: 0 : if (!follow_down_one(&path))
41 : : goto done;
42 : :
43 [ # # ]: 0 : if (is_autofs_dentry(path.dentry)) {
44 : 0 : struct autofs_sb_info *sbi = autofs_sbi(path.dentry->d_sb);
45 : :
46 : : /* This is an autofs submount, we can't expire it */
47 [ # # ]: 0 : if (autofs_type_indirect(sbi->type))
48 : : goto done;
49 : : }
50 : :
51 : : /* Not a submount, has a forced expire been requested */
52 [ # # ]: 0 : if (how & AUTOFS_EXP_FORCED) {
53 : : status = 0;
54 : : goto done;
55 : : }
56 : :
57 : : /* Update the expiry counter if fs is busy */
58 [ # # ]: 0 : if (!may_umount_tree(path.mnt)) {
59 : : struct autofs_info *ino;
60 : :
61 : : ino = autofs_dentry_ino(top);
62 : 0 : ino->last_used = jiffies;
63 : 0 : goto done;
64 : : }
65 : :
66 : : status = 0;
67 : : done:
68 : : pr_debug("returning = %d\n", status);
69 : 0 : path_put(&path);
70 : 0 : return status;
71 : : }
72 : :
73 : : /* p->d_lock held */
74 : 0 : static struct dentry *positive_after(struct dentry *p, struct dentry *child)
75 : : {
76 [ # # ]: 0 : if (child)
77 : 0 : child = list_next_entry(child, d_child);
78 : : else
79 : 0 : child = list_first_entry(&p->d_subdirs, struct dentry, d_child);
80 : :
81 [ # # ]: 0 : list_for_each_entry_from(child, &p->d_subdirs, d_child) {
82 : 0 : spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
83 [ # # ]: 0 : if (simple_positive(child)) {
84 : : dget_dlock(child);
85 : : spin_unlock(&child->d_lock);
86 : 0 : return child;
87 : : }
88 : : spin_unlock(&child->d_lock);
89 : : }
90 : :
91 : : return NULL;
92 : : }
93 : :
94 : : /*
95 : : * Calculate and dget next entry in the subdirs list under root.
96 : : */
97 : 0 : static struct dentry *get_next_positive_subdir(struct dentry *prev,
98 : : struct dentry *root)
99 : : {
100 : 0 : struct autofs_sb_info *sbi = autofs_sbi(root->d_sb);
101 : : struct dentry *q;
102 : :
103 : : spin_lock(&sbi->lookup_lock);
104 : : spin_lock(&root->d_lock);
105 : 0 : q = positive_after(root, prev);
106 : : spin_unlock(&root->d_lock);
107 : : spin_unlock(&sbi->lookup_lock);
108 : 0 : dput(prev);
109 : 0 : return q;
110 : : }
111 : :
112 : : /*
113 : : * Calculate and dget next entry in top down tree traversal.
114 : : */
115 : 0 : static struct dentry *get_next_positive_dentry(struct dentry *prev,
116 : : struct dentry *root)
117 : : {
118 : 0 : struct autofs_sb_info *sbi = autofs_sbi(root->d_sb);
119 : : struct dentry *p = prev, *ret = NULL, *d = NULL;
120 : :
121 [ # # ]: 0 : if (prev == NULL)
122 : 0 : return dget(root);
123 : :
124 : : spin_lock(&sbi->lookup_lock);
125 : : spin_lock(&p->d_lock);
126 : : while (1) {
127 : : struct dentry *parent;
128 : :
129 : 0 : ret = positive_after(p, d);
130 [ # # ]: 0 : if (ret || p == root)
131 : : break;
132 : 0 : parent = p->d_parent;
133 : : spin_unlock(&p->d_lock);
134 : : spin_lock(&parent->d_lock);
135 : : d = p;
136 : : p = parent;
137 : : }
138 : : spin_unlock(&p->d_lock);
139 : : spin_unlock(&sbi->lookup_lock);
140 : 0 : dput(prev);
141 : 0 : return ret;
142 : : }
143 : :
144 : : /*
145 : : * Check a direct mount point for busyness.
146 : : * Direct mounts have similar expiry semantics to tree mounts.
147 : : * The tree is not busy iff no mountpoints are busy and there are no
148 : : * autofs submounts.
149 : : */
150 : 0 : static int autofs_direct_busy(struct vfsmount *mnt,
151 : : struct dentry *top,
152 : : unsigned long timeout,
153 : : unsigned int how)
154 : : {
155 : : pr_debug("top %p %pd\n", top, top);
156 : :
157 : : /* Forced expire, user space handles busy mounts */
158 [ # # ]: 0 : if (how & AUTOFS_EXP_FORCED)
159 : : return 0;
160 : :
161 : : /* If it's busy update the expiry counters */
162 [ # # ]: 0 : if (!may_umount_tree(mnt)) {
163 : : struct autofs_info *ino;
164 : :
165 : : ino = autofs_dentry_ino(top);
166 [ # # ]: 0 : if (ino)
167 : 0 : ino->last_used = jiffies;
168 : : return 1;
169 : : }
170 : :
171 : : /* Timeout of a direct mount is determined by its top dentry */
172 [ # # ]: 0 : if (!autofs_can_expire(top, timeout, how))
173 : : return 1;
174 : :
175 : 0 : return 0;
176 : : }
177 : :
178 : : /*
179 : : * Check a directory tree of mount points for busyness
180 : : * The tree is not busy iff no mountpoints are busy
181 : : */
182 : 0 : static int autofs_tree_busy(struct vfsmount *mnt,
183 : : struct dentry *top,
184 : : unsigned long timeout,
185 : : unsigned int how)
186 : : {
187 : : struct autofs_info *top_ino = autofs_dentry_ino(top);
188 : : struct dentry *p;
189 : :
190 : : pr_debug("top %p %pd\n", top, top);
191 : :
192 : : /* Negative dentry - give up */
193 [ # # ]: 0 : if (!simple_positive(top))
194 : : return 1;
195 : :
196 : : p = NULL;
197 [ # # ]: 0 : while ((p = get_next_positive_dentry(p, top))) {
198 : : pr_debug("dentry %p %pd\n", p, p);
199 : :
200 : : /*
201 : : * Is someone visiting anywhere in the subtree ?
202 : : * If there's no mount we need to check the usage
203 : : * count for the autofs dentry.
204 : : * If the fs is busy update the expiry counter.
205 : : */
206 [ # # ]: 0 : if (d_mountpoint(p)) {
207 [ # # ]: 0 : if (autofs_mount_busy(mnt, p, how)) {
208 : 0 : top_ino->last_used = jiffies;
209 : 0 : dput(p);
210 : 0 : return 1;
211 : : }
212 : : } else {
213 : : struct autofs_info *ino = autofs_dentry_ino(p);
214 : : unsigned int ino_count = atomic_read(&ino->count);
215 : :
216 : : /* allow for dget above and top is already dgot */
217 [ # # ]: 0 : if (p == top)
218 : 0 : ino_count += 2;
219 : : else
220 : 0 : ino_count++;
221 : :
222 [ # # ]: 0 : if (d_count(p) > ino_count) {
223 : 0 : top_ino->last_used = jiffies;
224 : 0 : dput(p);
225 : 0 : return 1;
226 : : }
227 : : }
228 : : }
229 : :
230 : : /* Forced expire, user space handles busy mounts */
231 [ # # ]: 0 : if (how & AUTOFS_EXP_FORCED)
232 : : return 0;
233 : :
234 : : /* Timeout of a tree mount is ultimately determined by its top dentry */
235 [ # # ]: 0 : if (!autofs_can_expire(top, timeout, how))
236 : : return 1;
237 : :
238 : 0 : return 0;
239 : : }
240 : :
241 : 0 : static struct dentry *autofs_check_leaves(struct vfsmount *mnt,
242 : : struct dentry *parent,
243 : : unsigned long timeout,
244 : : unsigned int how)
245 : : {
246 : : struct dentry *p;
247 : :
248 : : pr_debug("parent %p %pd\n", parent, parent);
249 : :
250 : : p = NULL;
251 [ # # ]: 0 : while ((p = get_next_positive_dentry(p, parent))) {
252 : : pr_debug("dentry %p %pd\n", p, p);
253 : :
254 [ # # ]: 0 : if (d_mountpoint(p)) {
255 : : /* Can we umount this guy */
256 [ # # ]: 0 : if (autofs_mount_busy(mnt, p, how))
257 : 0 : continue;
258 : :
259 : : /* This isn't a submount so if a forced expire
260 : : * has been requested, user space handles busy
261 : : * mounts */
262 [ # # ]: 0 : if (how & AUTOFS_EXP_FORCED)
263 : 0 : return p;
264 : :
265 : : /* Can we expire this guy */
266 [ # # ]: 0 : if (autofs_can_expire(p, timeout, how))
267 : 0 : return p;
268 : : }
269 : : }
270 : : return NULL;
271 : : }
272 : :
273 : : /* Check if we can expire a direct mount (possibly a tree) */
274 : 0 : static struct dentry *autofs_expire_direct(struct super_block *sb,
275 : : struct vfsmount *mnt,
276 : : struct autofs_sb_info *sbi,
277 : : unsigned int how)
278 : : {
279 : 0 : struct dentry *root = dget(sb->s_root);
280 : : struct autofs_info *ino;
281 : : unsigned long timeout;
282 : :
283 [ # # ]: 0 : if (!root)
284 : : return NULL;
285 : :
286 : 0 : timeout = sbi->exp_timeout;
287 : :
288 [ # # ]: 0 : if (!autofs_direct_busy(mnt, root, timeout, how)) {
289 : : spin_lock(&sbi->fs_lock);
290 : : ino = autofs_dentry_ino(root);
291 : : /* No point expiring a pending mount */
292 [ # # ]: 0 : if (ino->flags & AUTOFS_INF_PENDING) {
293 : : spin_unlock(&sbi->fs_lock);
294 : : goto out;
295 : : }
296 : 0 : ino->flags |= AUTOFS_INF_WANT_EXPIRE;
297 : : spin_unlock(&sbi->fs_lock);
298 : 0 : synchronize_rcu();
299 [ # # ]: 0 : if (!autofs_direct_busy(mnt, root, timeout, how)) {
300 : : spin_lock(&sbi->fs_lock);
301 : 0 : ino->flags |= AUTOFS_INF_EXPIRING;
302 : : init_completion(&ino->expire_complete);
303 : : spin_unlock(&sbi->fs_lock);
304 : 0 : return root;
305 : : }
306 : : spin_lock(&sbi->fs_lock);
307 : 0 : ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
308 : : spin_unlock(&sbi->fs_lock);
309 : : }
310 : : out:
311 : 0 : dput(root);
312 : :
313 : 0 : return NULL;
314 : : }
315 : :
316 : : /* Check if 'dentry' should expire, or return a nearby
317 : : * dentry that is suitable.
318 : : * If returned dentry is different from arg dentry,
319 : : * then a dget() reference was taken, else not.
320 : : */
321 : 0 : static struct dentry *should_expire(struct dentry *dentry,
322 : : struct vfsmount *mnt,
323 : : unsigned long timeout,
324 : : unsigned int how)
325 : : {
326 : : struct autofs_info *ino = autofs_dentry_ino(dentry);
327 : : unsigned int ino_count;
328 : :
329 : : /* No point expiring a pending mount */
330 [ # # ]: 0 : if (ino->flags & AUTOFS_INF_PENDING)
331 : : return NULL;
332 : :
333 : : /*
334 : : * Case 1: (i) indirect mount or top level pseudo direct mount
335 : : * (autofs-4.1).
336 : : * (ii) indirect mount with offset mount, check the "/"
337 : : * offset (autofs-5.0+).
338 : : */
339 [ # # ]: 0 : if (d_mountpoint(dentry)) {
340 : : pr_debug("checking mountpoint %p %pd\n", dentry, dentry);
341 : :
342 : : /* Can we umount this guy */
343 [ # # ]: 0 : if (autofs_mount_busy(mnt, dentry, how))
344 : : return NULL;
345 : :
346 : : /* This isn't a submount so if a forced expire
347 : : * has been requested, user space handles busy
348 : : * mounts */
349 [ # # ]: 0 : if (how & AUTOFS_EXP_FORCED)
350 : : return dentry;
351 : :
352 : : /* Can we expire this guy */
353 [ # # ]: 0 : if (autofs_can_expire(dentry, timeout, how))
354 : 0 : return dentry;
355 : : return NULL;
356 : : }
357 : :
358 [ # # # # ]: 0 : if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
359 : : pr_debug("checking symlink %p %pd\n", dentry, dentry);
360 : :
361 : : /* Forced expire, user space handles busy mounts */
362 [ # # ]: 0 : if (how & AUTOFS_EXP_FORCED)
363 : : return dentry;
364 : :
365 : : /*
366 : : * A symlink can't be "busy" in the usual sense so
367 : : * just check last used for expire timeout.
368 : : */
369 [ # # ]: 0 : if (autofs_can_expire(dentry, timeout, how))
370 : 0 : return dentry;
371 : : return NULL;
372 : : }
373 : :
374 [ # # ]: 0 : if (simple_empty(dentry))
375 : : return NULL;
376 : :
377 : : /* Case 2: tree mount, expire iff entire tree is not busy */
378 [ # # ]: 0 : if (!(how & AUTOFS_EXP_LEAVES)) {
379 : : /* Not a forced expire? */
380 [ # # ]: 0 : if (!(how & AUTOFS_EXP_FORCED)) {
381 : : /* ref-walk currently on this dentry? */
382 : 0 : ino_count = atomic_read(&ino->count) + 1;
383 [ # # ]: 0 : if (d_count(dentry) > ino_count)
384 : : return NULL;
385 : : }
386 : :
387 [ # # ]: 0 : if (!autofs_tree_busy(mnt, dentry, timeout, how))
388 : 0 : return dentry;
389 : : /*
390 : : * Case 3: pseudo direct mount, expire individual leaves
391 : : * (autofs-4.1).
392 : : */
393 : : } else {
394 : : struct dentry *expired;
395 : :
396 : : /* Not a forced expire? */
397 [ # # ]: 0 : if (!(how & AUTOFS_EXP_FORCED)) {
398 : : /* ref-walk currently on this dentry? */
399 : 0 : ino_count = atomic_read(&ino->count) + 1;
400 [ # # ]: 0 : if (d_count(dentry) > ino_count)
401 : : return NULL;
402 : : }
403 : :
404 : 0 : expired = autofs_check_leaves(mnt, dentry, timeout, how);
405 [ # # ]: 0 : if (expired) {
406 [ # # ]: 0 : if (expired == dentry)
407 : 0 : dput(dentry);
408 : 0 : return expired;
409 : : }
410 : : }
411 : : return NULL;
412 : : }
413 : :
414 : : /*
415 : : * Find an eligible tree to time-out
416 : : * A tree is eligible if :-
417 : : * - it is unused by any user process
418 : : * - it has been unused for exp_timeout time
419 : : */
420 : 0 : static struct dentry *autofs_expire_indirect(struct super_block *sb,
421 : : struct vfsmount *mnt,
422 : : struct autofs_sb_info *sbi,
423 : : unsigned int how)
424 : : {
425 : : unsigned long timeout;
426 : 0 : struct dentry *root = sb->s_root;
427 : : struct dentry *dentry;
428 : : struct dentry *expired;
429 : : struct dentry *found;
430 : : struct autofs_info *ino;
431 : :
432 [ # # ]: 0 : if (!root)
433 : : return NULL;
434 : :
435 : 0 : timeout = sbi->exp_timeout;
436 : :
437 : : dentry = NULL;
438 [ # # ]: 0 : while ((dentry = get_next_positive_subdir(dentry, root))) {
439 : : spin_lock(&sbi->fs_lock);
440 : : ino = autofs_dentry_ino(dentry);
441 [ # # ]: 0 : if (ino->flags & AUTOFS_INF_WANT_EXPIRE) {
442 : : spin_unlock(&sbi->fs_lock);
443 : 0 : continue;
444 : : }
445 : : spin_unlock(&sbi->fs_lock);
446 : :
447 : 0 : expired = should_expire(dentry, mnt, timeout, how);
448 [ # # ]: 0 : if (!expired)
449 : 0 : continue;
450 : :
451 : : spin_lock(&sbi->fs_lock);
452 : : ino = autofs_dentry_ino(expired);
453 : 0 : ino->flags |= AUTOFS_INF_WANT_EXPIRE;
454 : : spin_unlock(&sbi->fs_lock);
455 : 0 : synchronize_rcu();
456 : :
457 : : /* Make sure a reference is not taken on found if
458 : : * things have changed.
459 : : */
460 : 0 : how &= ~AUTOFS_EXP_LEAVES;
461 : 0 : found = should_expire(expired, mnt, timeout, how);
462 [ # # ]: 0 : if (found != expired) { // something has changed, continue
463 : 0 : dput(found);
464 : : goto next;
465 : : }
466 : :
467 [ # # ]: 0 : if (expired != dentry)
468 : 0 : dput(dentry);
469 : :
470 : : spin_lock(&sbi->fs_lock);
471 : : goto found;
472 : : next:
473 : : spin_lock(&sbi->fs_lock);
474 : 0 : ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
475 : : spin_unlock(&sbi->fs_lock);
476 [ # # ]: 0 : if (expired != dentry)
477 : 0 : dput(expired);
478 : : }
479 : : return NULL;
480 : :
481 : : found:
482 : : pr_debug("returning %p %pd\n", expired, expired);
483 : 0 : ino->flags |= AUTOFS_INF_EXPIRING;
484 : : init_completion(&ino->expire_complete);
485 : : spin_unlock(&sbi->fs_lock);
486 : 0 : return expired;
487 : : }
488 : :
489 : 0 : int autofs_expire_wait(const struct path *path, int rcu_walk)
490 : : {
491 : 0 : struct dentry *dentry = path->dentry;
492 : 0 : struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
493 : : struct autofs_info *ino = autofs_dentry_ino(dentry);
494 : : int status;
495 : : int state;
496 : :
497 : : /* Block on any pending expire */
498 [ # # ]: 0 : if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE))
499 : : return 0;
500 [ # # ]: 0 : if (rcu_walk)
501 : : return -ECHILD;
502 : :
503 : : retry:
504 : : spin_lock(&sbi->fs_lock);
505 : 0 : state = ino->flags & (AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING);
506 [ # # ]: 0 : if (state == AUTOFS_INF_WANT_EXPIRE) {
507 : : spin_unlock(&sbi->fs_lock);
508 : : /*
509 : : * Possibly being selected for expire, wait until
510 : : * it's selected or not.
511 : : */
512 : 0 : schedule_timeout_uninterruptible(HZ/10);
513 : 0 : goto retry;
514 : : }
515 [ # # ]: 0 : if (state & AUTOFS_INF_EXPIRING) {
516 : : spin_unlock(&sbi->fs_lock);
517 : :
518 : : pr_debug("waiting for expire %p name=%pd\n", dentry, dentry);
519 : :
520 : 0 : status = autofs_wait(sbi, path, NFY_NONE);
521 : 0 : wait_for_completion(&ino->expire_complete);
522 : :
523 : : pr_debug("expire done status=%d\n", status);
524 : :
525 [ # # ]: 0 : if (d_unhashed(dentry))
526 : : return -EAGAIN;
527 : :
528 : 0 : return status;
529 : : }
530 : : spin_unlock(&sbi->fs_lock);
531 : :
532 : 0 : return 0;
533 : : }
534 : :
535 : : /* Perform an expiry operation */
536 : 0 : int autofs_expire_run(struct super_block *sb,
537 : : struct vfsmount *mnt,
538 : : struct autofs_sb_info *sbi,
539 : : struct autofs_packet_expire __user *pkt_p)
540 : : {
541 : : struct autofs_packet_expire pkt;
542 : : struct autofs_info *ino;
543 : : struct dentry *dentry;
544 : : int ret = 0;
545 : :
546 : 0 : memset(&pkt, 0, sizeof(pkt));
547 : :
548 : 0 : pkt.hdr.proto_version = sbi->version;
549 : 0 : pkt.hdr.type = autofs_ptype_expire;
550 : :
551 : 0 : dentry = autofs_expire_indirect(sb, mnt, sbi, 0);
552 [ # # ]: 0 : if (!dentry)
553 : : return -EAGAIN;
554 : :
555 : 0 : pkt.len = dentry->d_name.len;
556 : 0 : memcpy(pkt.name, dentry->d_name.name, pkt.len);
557 : 0 : pkt.name[pkt.len] = '\0';
558 : :
559 [ # # ]: 0 : if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)))
560 : : ret = -EFAULT;
561 : :
562 : : spin_lock(&sbi->fs_lock);
563 : : ino = autofs_dentry_ino(dentry);
564 : : /* avoid rapid-fire expire attempts if expiry fails */
565 : 0 : ino->last_used = jiffies;
566 : 0 : ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
567 : 0 : complete_all(&ino->expire_complete);
568 : : spin_unlock(&sbi->fs_lock);
569 : :
570 : 0 : dput(dentry);
571 : :
572 : 0 : return ret;
573 : : }
574 : :
575 : 0 : int autofs_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
576 : : struct autofs_sb_info *sbi, unsigned int how)
577 : : {
578 : : struct dentry *dentry;
579 : : int ret = -EAGAIN;
580 : :
581 [ # # ]: 0 : if (autofs_type_trigger(sbi->type))
582 : 0 : dentry = autofs_expire_direct(sb, mnt, sbi, how);
583 : : else
584 : 0 : dentry = autofs_expire_indirect(sb, mnt, sbi, how);
585 : :
586 [ # # ]: 0 : if (dentry) {
587 : : struct autofs_info *ino = autofs_dentry_ino(dentry);
588 : 0 : const struct path path = { .mnt = mnt, .dentry = dentry };
589 : :
590 : : /* This is synchronous because it makes the daemon a
591 : : * little easier
592 : : */
593 : 0 : ret = autofs_wait(sbi, &path, NFY_EXPIRE);
594 : :
595 : : spin_lock(&sbi->fs_lock);
596 : : /* avoid rapid-fire expire attempts if expiry fails */
597 : 0 : ino->last_used = jiffies;
598 : 0 : ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
599 : 0 : complete_all(&ino->expire_complete);
600 : : spin_unlock(&sbi->fs_lock);
601 : 0 : dput(dentry);
602 : : }
603 : :
604 : 0 : return ret;
605 : : }
606 : :
607 : : /*
608 : : * Call repeatedly until it returns -EAGAIN, meaning there's nothing
609 : : * more to be done.
610 : : */
611 : 0 : int autofs_expire_multi(struct super_block *sb, struct vfsmount *mnt,
612 : : struct autofs_sb_info *sbi, int __user *arg)
613 : : {
614 : : unsigned int how = 0;
615 : :
616 [ # # # # ]: 0 : if (arg && get_user(how, arg))
617 : : return -EFAULT;
618 : :
619 : 0 : return autofs_do_expire_multi(sb, mnt, sbi, how);
620 : : }
|