diff options
Diffstat (limited to 'fs/autofs4/root.c')
-rw-r--r-- | fs/autofs4/root.c | 79 |
1 files changed, 49 insertions, 30 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 30cc9ddf4b70..40ca9360caef 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -17,8 +17,11 @@ | |||
17 | #include <linux/stat.h> | 17 | #include <linux/stat.h> |
18 | #include <linux/param.h> | 18 | #include <linux/param.h> |
19 | #include <linux/time.h> | 19 | #include <linux/time.h> |
20 | #include <linux/spinlock.h> | ||
20 | #include "autofs_i.h" | 21 | #include "autofs_i.h" |
21 | 22 | ||
23 | DEFINE_SPINLOCK(autofs4_lock); | ||
24 | |||
22 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); | 25 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); |
23 | static int autofs4_dir_unlink(struct inode *,struct dentry *); | 26 | static int autofs4_dir_unlink(struct inode *,struct dentry *); |
24 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); | 27 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); |
@@ -225,12 +228,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
225 | * autofs file system so just let the libfs routines handle | 228 | * autofs file system so just let the libfs routines handle |
226 | * it. | 229 | * it. |
227 | */ | 230 | */ |
228 | spin_lock(&dcache_lock); | 231 | spin_lock(&autofs4_lock); |
232 | spin_lock(&dentry->d_lock); | ||
229 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 233 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
230 | spin_unlock(&dcache_lock); | 234 | spin_unlock(&dentry->d_lock); |
235 | spin_unlock(&autofs4_lock); | ||
231 | return -ENOENT; | 236 | return -ENOENT; |
232 | } | 237 | } |
233 | spin_unlock(&dcache_lock); | 238 | spin_unlock(&dentry->d_lock); |
239 | spin_unlock(&autofs4_lock); | ||
234 | 240 | ||
235 | out: | 241 | out: |
236 | return dcache_dir_open(inode, file); | 242 | return dcache_dir_open(inode, file); |
@@ -299,9 +305,9 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
299 | /* We trigger a mount for almost all flags */ | 305 | /* We trigger a mount for almost all flags */ |
300 | lookup_type = autofs4_need_mount(nd->flags); | 306 | lookup_type = autofs4_need_mount(nd->flags); |
301 | spin_lock(&sbi->fs_lock); | 307 | spin_lock(&sbi->fs_lock); |
302 | spin_lock(&dcache_lock); | 308 | spin_lock(&autofs4_lock); |
303 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | 309 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { |
304 | spin_unlock(&dcache_lock); | 310 | spin_unlock(&autofs4_lock); |
305 | spin_unlock(&sbi->fs_lock); | 311 | spin_unlock(&sbi->fs_lock); |
306 | goto follow; | 312 | goto follow; |
307 | } | 313 | } |
@@ -311,10 +317,11 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
311 | * multi-mount with no root mount offset. So don't try to | 317 | * multi-mount with no root mount offset. So don't try to |
312 | * mount it again. | 318 | * mount it again. |
313 | */ | 319 | */ |
320 | spin_lock(&dentry->d_lock); | ||
314 | if (ino->flags & AUTOFS_INF_PENDING || | 321 | if (ino->flags & AUTOFS_INF_PENDING || |
315 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { | 322 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { |
316 | ino->flags |= AUTOFS_INF_PENDING; | 323 | ino->flags |= AUTOFS_INF_PENDING; |
317 | spin_unlock(&dcache_lock); | 324 | spin_unlock(&dentry->d_lock); |
318 | spin_unlock(&sbi->fs_lock); | 325 | spin_unlock(&sbi->fs_lock); |
319 | 326 | ||
320 | status = try_to_fill_dentry(dentry); | 327 | status = try_to_fill_dentry(dentry); |
@@ -322,14 +329,16 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
322 | spin_lock(&sbi->fs_lock); | 329 | spin_lock(&sbi->fs_lock); |
323 | ino->flags &= ~AUTOFS_INF_PENDING; | 330 | ino->flags &= ~AUTOFS_INF_PENDING; |
324 | spin_unlock(&sbi->fs_lock); | 331 | spin_unlock(&sbi->fs_lock); |
332 | spin_unlock(&autofs4_lock); | ||
325 | 333 | ||
326 | if (status) | 334 | if (status) |
327 | goto out_error; | 335 | goto out_error; |
328 | 336 | ||
329 | goto follow; | 337 | goto follow; |
330 | } | 338 | } |
331 | spin_unlock(&dcache_lock); | 339 | spin_unlock(&dentry->d_lock); |
332 | spin_unlock(&sbi->fs_lock); | 340 | spin_unlock(&sbi->fs_lock); |
341 | spin_unlock(&autofs4_lock); | ||
333 | follow: | 342 | follow: |
334 | /* | 343 | /* |
335 | * If there is no root mount it must be an autofs | 344 | * If there is no root mount it must be an autofs |
@@ -380,7 +389,7 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
380 | mutex_aquired = mutex_trylock(&dir->i_mutex); | 389 | mutex_aquired = mutex_trylock(&dir->i_mutex); |
381 | 390 | ||
382 | spin_lock(&sbi->fs_lock); | 391 | spin_lock(&sbi->fs_lock); |
383 | spin_lock(&dcache_lock); | 392 | spin_lock(&autofs4_lock); |
384 | /* Pending dentry */ | 393 | /* Pending dentry */ |
385 | if (autofs4_ispending(dentry)) { | 394 | if (autofs4_ispending(dentry)) { |
386 | int status; | 395 | int status; |
@@ -394,11 +403,11 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
394 | ino->flags |= AUTOFS_INF_PENDING; | 403 | ino->flags |= AUTOFS_INF_PENDING; |
395 | if (!mutex_aquired) { | 404 | if (!mutex_aquired) { |
396 | autofs4_revalidate_drop(dentry, entry); | 405 | autofs4_revalidate_drop(dentry, entry); |
397 | spin_unlock(&dcache_lock); | 406 | spin_unlock(&autofs4_lock); |
398 | spin_unlock(&sbi->fs_lock); | 407 | spin_unlock(&sbi->fs_lock); |
399 | return 0; | 408 | return 0; |
400 | } | 409 | } |
401 | spin_unlock(&dcache_lock); | 410 | spin_unlock(&autofs4_lock); |
402 | spin_unlock(&sbi->fs_lock); | 411 | spin_unlock(&sbi->fs_lock); |
403 | mutex_unlock(&dir->i_mutex); | 412 | mutex_unlock(&dir->i_mutex); |
404 | kfree(entry); | 413 | kfree(entry); |
@@ -445,11 +454,11 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
445 | ino->flags |= AUTOFS_INF_PENDING; | 454 | ino->flags |= AUTOFS_INF_PENDING; |
446 | if (!mutex_aquired) { | 455 | if (!mutex_aquired) { |
447 | autofs4_revalidate_drop(dentry, entry); | 456 | autofs4_revalidate_drop(dentry, entry); |
448 | spin_unlock(&dcache_lock); | 457 | spin_unlock(&autofs4_lock); |
449 | spin_unlock(&sbi->fs_lock); | 458 | spin_unlock(&sbi->fs_lock); |
450 | return 0; | 459 | return 0; |
451 | } | 460 | } |
452 | spin_unlock(&dcache_lock); | 461 | spin_unlock(&autofs4_lock); |
453 | spin_unlock(&sbi->fs_lock); | 462 | spin_unlock(&sbi->fs_lock); |
454 | mutex_unlock(&dir->i_mutex); | 463 | mutex_unlock(&dir->i_mutex); |
455 | kfree(entry); | 464 | kfree(entry); |
@@ -470,7 +479,7 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
470 | return status; | 479 | return status; |
471 | } | 480 | } |
472 | } | 481 | } |
473 | spin_unlock(&dcache_lock); | 482 | spin_unlock(&autofs4_lock); |
474 | spin_unlock(&sbi->fs_lock); | 483 | spin_unlock(&sbi->fs_lock); |
475 | 484 | ||
476 | if (mutex_aquired) | 485 | if (mutex_aquired) |
@@ -544,7 +553,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
544 | struct list_head *p, *head; | 553 | struct list_head *p, *head; |
545 | 554 | ||
546 | restart: | 555 | restart: |
547 | spin_lock(&dcache_lock); | 556 | spin_lock(&autofs4_lock); |
548 | spin_lock(&sbi->lookup_lock); | 557 | spin_lock(&sbi->lookup_lock); |
549 | head = &sbi->active_list; | 558 | head = &sbi->active_list; |
550 | list_for_each(p, head) { | 559 | list_for_each(p, head) { |
@@ -558,15 +567,15 @@ restart: | |||
558 | spin_lock(&active->d_lock); | 567 | spin_lock(&active->d_lock); |
559 | 568 | ||
560 | /* Already gone? */ | 569 | /* Already gone? */ |
561 | if (atomic_read(&active->d_count) == 0) | 570 | if (atomic_read(&dentry->d_count) == 0) |
562 | goto next; | 571 | goto next; |
563 | 572 | ||
564 | if (active->d_inode && IS_DEADDIR(active->d_inode)) { | 573 | if (active->d_inode && IS_DEADDIR(active->d_inode)) { |
565 | if (!list_empty(&ino->rehash_list)) { | 574 | if (!list_empty(&ino->rehash_list)) { |
566 | dget(active); | 575 | dget_dlock(active); |
567 | spin_unlock(&active->d_lock); | 576 | spin_unlock(&active->d_lock); |
568 | spin_unlock(&sbi->lookup_lock); | 577 | spin_unlock(&sbi->lookup_lock); |
569 | spin_unlock(&dcache_lock); | 578 | spin_unlock(&autofs4_lock); |
570 | autofs4_remove_rehash_entrys(ino); | 579 | autofs4_remove_rehash_entrys(ino); |
571 | dput(active); | 580 | dput(active); |
572 | goto restart; | 581 | goto restart; |
@@ -586,16 +595,16 @@ restart: | |||
586 | if (memcmp(qstr->name, str, len)) | 595 | if (memcmp(qstr->name, str, len)) |
587 | goto next; | 596 | goto next; |
588 | 597 | ||
589 | dget(active); | 598 | dget_dlock(active); |
590 | spin_unlock(&active->d_lock); | 599 | spin_unlock(&active->d_lock); |
591 | spin_unlock(&sbi->lookup_lock); | 600 | spin_unlock(&sbi->lookup_lock); |
592 | spin_unlock(&dcache_lock); | 601 | spin_unlock(&autofs4_lock); |
593 | return active; | 602 | return active; |
594 | next: | 603 | next: |
595 | spin_unlock(&active->d_lock); | 604 | spin_unlock(&active->d_lock); |
596 | } | 605 | } |
597 | spin_unlock(&sbi->lookup_lock); | 606 | spin_unlock(&sbi->lookup_lock); |
598 | spin_unlock(&dcache_lock); | 607 | spin_unlock(&autofs4_lock); |
599 | 608 | ||
600 | return NULL; | 609 | return NULL; |
601 | } | 610 | } |
@@ -610,7 +619,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
610 | const unsigned char *str = name->name; | 619 | const unsigned char *str = name->name; |
611 | struct list_head *p, *head; | 620 | struct list_head *p, *head; |
612 | 621 | ||
613 | spin_lock(&dcache_lock); | 622 | spin_lock(&autofs4_lock); |
614 | spin_lock(&sbi->lookup_lock); | 623 | spin_lock(&sbi->lookup_lock); |
615 | head = &sbi->expiring_list; | 624 | head = &sbi->expiring_list; |
616 | list_for_each(p, head) { | 625 | list_for_each(p, head) { |
@@ -639,16 +648,16 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
639 | if (memcmp(qstr->name, str, len)) | 648 | if (memcmp(qstr->name, str, len)) |
640 | goto next; | 649 | goto next; |
641 | 650 | ||
642 | dget(expiring); | 651 | dget_dlock(expiring); |
643 | spin_unlock(&expiring->d_lock); | 652 | spin_unlock(&expiring->d_lock); |
644 | spin_unlock(&sbi->lookup_lock); | 653 | spin_unlock(&sbi->lookup_lock); |
645 | spin_unlock(&dcache_lock); | 654 | spin_unlock(&autofs4_lock); |
646 | return expiring; | 655 | return expiring; |
647 | next: | 656 | next: |
648 | spin_unlock(&expiring->d_lock); | 657 | spin_unlock(&expiring->d_lock); |
649 | } | 658 | } |
650 | spin_unlock(&sbi->lookup_lock); | 659 | spin_unlock(&sbi->lookup_lock); |
651 | spin_unlock(&dcache_lock); | 660 | spin_unlock(&autofs4_lock); |
652 | 661 | ||
653 | return NULL; | 662 | return NULL; |
654 | } | 663 | } |
@@ -909,11 +918,15 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
909 | 918 | ||
910 | dir->i_mtime = CURRENT_TIME; | 919 | dir->i_mtime = CURRENT_TIME; |
911 | 920 | ||
912 | spin_lock(&dcache_lock); | 921 | spin_lock(&autofs4_lock); |
922 | spin_lock(&sbi->lookup_lock); | ||
923 | if (list_empty(&ino->expiring)) | ||
924 | list_add(&ino->expiring, &sbi->expiring_list); | ||
925 | spin_unlock(&sbi->lookup_lock); | ||
913 | spin_lock(&dentry->d_lock); | 926 | spin_lock(&dentry->d_lock); |
914 | __d_drop(dentry); | 927 | __d_drop(dentry); |
915 | spin_unlock(&dentry->d_lock); | 928 | spin_unlock(&dentry->d_lock); |
916 | spin_unlock(&dcache_lock); | 929 | spin_unlock(&autofs4_lock); |
917 | 930 | ||
918 | return 0; | 931 | return 0; |
919 | } | 932 | } |
@@ -930,15 +943,21 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
930 | if (!autofs4_oz_mode(sbi)) | 943 | if (!autofs4_oz_mode(sbi)) |
931 | return -EACCES; | 944 | return -EACCES; |
932 | 945 | ||
933 | spin_lock(&dcache_lock); | 946 | spin_lock(&autofs4_lock); |
947 | spin_lock(&sbi->lookup_lock); | ||
948 | spin_lock(&dentry->d_lock); | ||
934 | if (!list_empty(&dentry->d_subdirs)) { | 949 | if (!list_empty(&dentry->d_subdirs)) { |
935 | spin_unlock(&dcache_lock); | 950 | spin_unlock(&dentry->d_lock); |
951 | spin_unlock(&sbi->lookup_lock); | ||
952 | spin_unlock(&autofs4_lock); | ||
936 | return -ENOTEMPTY; | 953 | return -ENOTEMPTY; |
937 | } | 954 | } |
938 | spin_lock(&dentry->d_lock); | 955 | if (list_empty(&ino->expiring)) |
956 | list_add(&ino->expiring, &sbi->expiring_list); | ||
957 | spin_unlock(&sbi->lookup_lock); | ||
939 | __d_drop(dentry); | 958 | __d_drop(dentry); |
940 | spin_unlock(&dentry->d_lock); | 959 | spin_unlock(&dentry->d_lock); |
941 | spin_unlock(&dcache_lock); | 960 | spin_unlock(&autofs4_lock); |
942 | 961 | ||
943 | if (atomic_dec_and_test(&ino->count)) { | 962 | if (atomic_dec_and_test(&ino->count)) { |
944 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 963 | p_ino = autofs4_dentry_ino(dentry->d_parent); |