diff options
author | Jaroslav Kysela <perex@hera.kernel.org> | 2005-06-21 10:39:41 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@hera.kernel.org> | 2005-06-21 10:39:41 -0400 |
commit | fae6ec69c84d71b1d5bda9ede1a262c1681684aa (patch) | |
tree | eb4aff9a5c2b7d04ce09a3717bb1dd4a79fe7595 /fs/namei.c | |
parent | bbc0274e9bb2e3f1d724d445a2bd32566b9b66f7 (diff) | |
parent | 1d345dac1f30af1cd9f3a1faa12f9f18f17f236e (diff) |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 153 |
1 files changed, 86 insertions, 67 deletions
diff --git a/fs/namei.c b/fs/namei.c index dd78f01b6de8..a7f7f44119b3 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -493,12 +493,21 @@ fail: | |||
493 | return PTR_ERR(link); | 493 | return PTR_ERR(link); |
494 | } | 494 | } |
495 | 495 | ||
496 | static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) | 496 | struct path { |
497 | struct vfsmount *mnt; | ||
498 | struct dentry *dentry; | ||
499 | }; | ||
500 | |||
501 | static inline int __do_follow_link(struct path *path, struct nameidata *nd) | ||
497 | { | 502 | { |
498 | int error; | 503 | int error; |
504 | struct dentry *dentry = path->dentry; | ||
499 | 505 | ||
500 | touch_atime(nd->mnt, dentry); | 506 | touch_atime(path->mnt, dentry); |
501 | nd_set_link(nd, NULL); | 507 | nd_set_link(nd, NULL); |
508 | |||
509 | if (path->mnt == nd->mnt) | ||
510 | mntget(path->mnt); | ||
502 | error = dentry->d_inode->i_op->follow_link(dentry, nd); | 511 | error = dentry->d_inode->i_op->follow_link(dentry, nd); |
503 | if (!error) { | 512 | if (!error) { |
504 | char *s = nd_get_link(nd); | 513 | char *s = nd_get_link(nd); |
@@ -507,6 +516,8 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
507 | if (dentry->d_inode->i_op->put_link) | 516 | if (dentry->d_inode->i_op->put_link) |
508 | dentry->d_inode->i_op->put_link(dentry, nd); | 517 | dentry->d_inode->i_op->put_link(dentry, nd); |
509 | } | 518 | } |
519 | dput(dentry); | ||
520 | mntput(path->mnt); | ||
510 | 521 | ||
511 | return error; | 522 | return error; |
512 | } | 523 | } |
@@ -518,7 +529,7 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
518 | * Without that kind of total limit, nasty chains of consecutive | 529 | * Without that kind of total limit, nasty chains of consecutive |
519 | * symlinks can cause almost arbitrarily long lookups. | 530 | * symlinks can cause almost arbitrarily long lookups. |
520 | */ | 531 | */ |
521 | static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) | 532 | static inline int do_follow_link(struct path *path, struct nameidata *nd) |
522 | { | 533 | { |
523 | int err = -ELOOP; | 534 | int err = -ELOOP; |
524 | if (current->link_count >= MAX_NESTED_LINKS) | 535 | if (current->link_count >= MAX_NESTED_LINKS) |
@@ -527,17 +538,20 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
527 | goto loop; | 538 | goto loop; |
528 | BUG_ON(nd->depth >= MAX_NESTED_LINKS); | 539 | BUG_ON(nd->depth >= MAX_NESTED_LINKS); |
529 | cond_resched(); | 540 | cond_resched(); |
530 | err = security_inode_follow_link(dentry, nd); | 541 | err = security_inode_follow_link(path->dentry, nd); |
531 | if (err) | 542 | if (err) |
532 | goto loop; | 543 | goto loop; |
533 | current->link_count++; | 544 | current->link_count++; |
534 | current->total_link_count++; | 545 | current->total_link_count++; |
535 | nd->depth++; | 546 | nd->depth++; |
536 | err = __do_follow_link(dentry, nd); | 547 | err = __do_follow_link(path, nd); |
537 | current->link_count--; | 548 | current->link_count--; |
538 | nd->depth--; | 549 | nd->depth--; |
539 | return err; | 550 | return err; |
540 | loop: | 551 | loop: |
552 | dput(path->dentry); | ||
553 | if (path->mnt != nd->mnt) | ||
554 | mntput(path->mnt); | ||
541 | path_release(nd); | 555 | path_release(nd); |
542 | return err; | 556 | return err; |
543 | } | 557 | } |
@@ -565,87 +579,91 @@ int follow_up(struct vfsmount **mnt, struct dentry **dentry) | |||
565 | /* no need for dcache_lock, as serialization is taken care in | 579 | /* no need for dcache_lock, as serialization is taken care in |
566 | * namespace.c | 580 | * namespace.c |
567 | */ | 581 | */ |
568 | static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) | 582 | static int __follow_mount(struct path *path) |
569 | { | 583 | { |
570 | int res = 0; | 584 | int res = 0; |
585 | while (d_mountpoint(path->dentry)) { | ||
586 | struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry); | ||
587 | if (!mounted) | ||
588 | break; | ||
589 | dput(path->dentry); | ||
590 | if (res) | ||
591 | mntput(path->mnt); | ||
592 | path->mnt = mounted; | ||
593 | path->dentry = dget(mounted->mnt_root); | ||
594 | res = 1; | ||
595 | } | ||
596 | return res; | ||
597 | } | ||
598 | |||
599 | static void follow_mount(struct vfsmount **mnt, struct dentry **dentry) | ||
600 | { | ||
571 | while (d_mountpoint(*dentry)) { | 601 | while (d_mountpoint(*dentry)) { |
572 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); | 602 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); |
573 | if (!mounted) | 603 | if (!mounted) |
574 | break; | 604 | break; |
605 | dput(*dentry); | ||
575 | mntput(*mnt); | 606 | mntput(*mnt); |
576 | *mnt = mounted; | 607 | *mnt = mounted; |
577 | dput(*dentry); | ||
578 | *dentry = dget(mounted->mnt_root); | 608 | *dentry = dget(mounted->mnt_root); |
579 | res = 1; | ||
580 | } | 609 | } |
581 | return res; | ||
582 | } | 610 | } |
583 | 611 | ||
584 | /* no need for dcache_lock, as serialization is taken care in | 612 | /* no need for dcache_lock, as serialization is taken care in |
585 | * namespace.c | 613 | * namespace.c |
586 | */ | 614 | */ |
587 | static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry) | 615 | int follow_down(struct vfsmount **mnt, struct dentry **dentry) |
588 | { | 616 | { |
589 | struct vfsmount *mounted; | 617 | struct vfsmount *mounted; |
590 | 618 | ||
591 | mounted = lookup_mnt(*mnt, *dentry); | 619 | mounted = lookup_mnt(*mnt, *dentry); |
592 | if (mounted) { | 620 | if (mounted) { |
621 | dput(*dentry); | ||
593 | mntput(*mnt); | 622 | mntput(*mnt); |
594 | *mnt = mounted; | 623 | *mnt = mounted; |
595 | dput(*dentry); | ||
596 | *dentry = dget(mounted->mnt_root); | 624 | *dentry = dget(mounted->mnt_root); |
597 | return 1; | 625 | return 1; |
598 | } | 626 | } |
599 | return 0; | 627 | return 0; |
600 | } | 628 | } |
601 | 629 | ||
602 | int follow_down(struct vfsmount **mnt, struct dentry **dentry) | 630 | static inline void follow_dotdot(struct nameidata *nd) |
603 | { | ||
604 | return __follow_down(mnt,dentry); | ||
605 | } | ||
606 | |||
607 | static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) | ||
608 | { | 631 | { |
609 | while(1) { | 632 | while(1) { |
610 | struct vfsmount *parent; | 633 | struct vfsmount *parent; |
611 | struct dentry *old = *dentry; | 634 | struct dentry *old = nd->dentry; |
612 | 635 | ||
613 | read_lock(¤t->fs->lock); | 636 | read_lock(¤t->fs->lock); |
614 | if (*dentry == current->fs->root && | 637 | if (nd->dentry == current->fs->root && |
615 | *mnt == current->fs->rootmnt) { | 638 | nd->mnt == current->fs->rootmnt) { |
616 | read_unlock(¤t->fs->lock); | 639 | read_unlock(¤t->fs->lock); |
617 | break; | 640 | break; |
618 | } | 641 | } |
619 | read_unlock(¤t->fs->lock); | 642 | read_unlock(¤t->fs->lock); |
620 | spin_lock(&dcache_lock); | 643 | spin_lock(&dcache_lock); |
621 | if (*dentry != (*mnt)->mnt_root) { | 644 | if (nd->dentry != nd->mnt->mnt_root) { |
622 | *dentry = dget((*dentry)->d_parent); | 645 | nd->dentry = dget(nd->dentry->d_parent); |
623 | spin_unlock(&dcache_lock); | 646 | spin_unlock(&dcache_lock); |
624 | dput(old); | 647 | dput(old); |
625 | break; | 648 | break; |
626 | } | 649 | } |
627 | spin_unlock(&dcache_lock); | 650 | spin_unlock(&dcache_lock); |
628 | spin_lock(&vfsmount_lock); | 651 | spin_lock(&vfsmount_lock); |
629 | parent = (*mnt)->mnt_parent; | 652 | parent = nd->mnt->mnt_parent; |
630 | if (parent == *mnt) { | 653 | if (parent == nd->mnt) { |
631 | spin_unlock(&vfsmount_lock); | 654 | spin_unlock(&vfsmount_lock); |
632 | break; | 655 | break; |
633 | } | 656 | } |
634 | mntget(parent); | 657 | mntget(parent); |
635 | *dentry = dget((*mnt)->mnt_mountpoint); | 658 | nd->dentry = dget(nd->mnt->mnt_mountpoint); |
636 | spin_unlock(&vfsmount_lock); | 659 | spin_unlock(&vfsmount_lock); |
637 | dput(old); | 660 | dput(old); |
638 | mntput(*mnt); | 661 | mntput(nd->mnt); |
639 | *mnt = parent; | 662 | nd->mnt = parent; |
640 | } | 663 | } |
641 | follow_mount(mnt, dentry); | 664 | follow_mount(&nd->mnt, &nd->dentry); |
642 | } | 665 | } |
643 | 666 | ||
644 | struct path { | ||
645 | struct vfsmount *mnt; | ||
646 | struct dentry *dentry; | ||
647 | }; | ||
648 | |||
649 | /* | 667 | /* |
650 | * It's more convoluted than I'd like it to be, but... it's still fairly | 668 | * It's more convoluted than I'd like it to be, but... it's still fairly |
651 | * small and for now I'd prefer to have fast path as straight as possible. | 669 | * small and for now I'd prefer to have fast path as straight as possible. |
@@ -664,6 +682,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
664 | done: | 682 | done: |
665 | path->mnt = mnt; | 683 | path->mnt = mnt; |
666 | path->dentry = dentry; | 684 | path->dentry = dentry; |
685 | __follow_mount(path); | ||
667 | return 0; | 686 | return 0; |
668 | 687 | ||
669 | need_lookup: | 688 | need_lookup: |
@@ -751,7 +770,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
751 | case 2: | 770 | case 2: |
752 | if (this.name[1] != '.') | 771 | if (this.name[1] != '.') |
753 | break; | 772 | break; |
754 | follow_dotdot(&nd->mnt, &nd->dentry); | 773 | follow_dotdot(nd); |
755 | inode = nd->dentry->d_inode; | 774 | inode = nd->dentry->d_inode; |
756 | /* fallthrough */ | 775 | /* fallthrough */ |
757 | case 1: | 776 | case 1: |
@@ -771,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
771 | err = do_lookup(nd, &this, &next); | 790 | err = do_lookup(nd, &this, &next); |
772 | if (err) | 791 | if (err) |
773 | break; | 792 | break; |
774 | /* Check mountpoints.. */ | ||
775 | follow_mount(&next.mnt, &next.dentry); | ||
776 | 793 | ||
777 | err = -ENOENT; | 794 | err = -ENOENT; |
778 | inode = next.dentry->d_inode; | 795 | inode = next.dentry->d_inode; |
@@ -783,10 +800,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
783 | goto out_dput; | 800 | goto out_dput; |
784 | 801 | ||
785 | if (inode->i_op->follow_link) { | 802 | if (inode->i_op->follow_link) { |
786 | mntget(next.mnt); | 803 | err = do_follow_link(&next, nd); |
787 | err = do_follow_link(next.dentry, nd); | ||
788 | dput(next.dentry); | ||
789 | mntput(next.mnt); | ||
790 | if (err) | 804 | if (err) |
791 | goto return_err; | 805 | goto return_err; |
792 | err = -ENOENT; | 806 | err = -ENOENT; |
@@ -798,6 +812,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
798 | break; | 812 | break; |
799 | } else { | 813 | } else { |
800 | dput(nd->dentry); | 814 | dput(nd->dentry); |
815 | if (nd->mnt != next.mnt) | ||
816 | mntput(nd->mnt); | ||
801 | nd->mnt = next.mnt; | 817 | nd->mnt = next.mnt; |
802 | nd->dentry = next.dentry; | 818 | nd->dentry = next.dentry; |
803 | } | 819 | } |
@@ -819,7 +835,7 @@ last_component: | |||
819 | case 2: | 835 | case 2: |
820 | if (this.name[1] != '.') | 836 | if (this.name[1] != '.') |
821 | break; | 837 | break; |
822 | follow_dotdot(&nd->mnt, &nd->dentry); | 838 | follow_dotdot(nd); |
823 | inode = nd->dentry->d_inode; | 839 | inode = nd->dentry->d_inode; |
824 | /* fallthrough */ | 840 | /* fallthrough */ |
825 | case 1: | 841 | case 1: |
@@ -833,19 +849,17 @@ last_component: | |||
833 | err = do_lookup(nd, &this, &next); | 849 | err = do_lookup(nd, &this, &next); |
834 | if (err) | 850 | if (err) |
835 | break; | 851 | break; |
836 | follow_mount(&next.mnt, &next.dentry); | ||
837 | inode = next.dentry->d_inode; | 852 | inode = next.dentry->d_inode; |
838 | if ((lookup_flags & LOOKUP_FOLLOW) | 853 | if ((lookup_flags & LOOKUP_FOLLOW) |
839 | && inode && inode->i_op && inode->i_op->follow_link) { | 854 | && inode && inode->i_op && inode->i_op->follow_link) { |
840 | mntget(next.mnt); | 855 | err = do_follow_link(&next, nd); |
841 | err = do_follow_link(next.dentry, nd); | ||
842 | dput(next.dentry); | ||
843 | mntput(next.mnt); | ||
844 | if (err) | 856 | if (err) |
845 | goto return_err; | 857 | goto return_err; |
846 | inode = nd->dentry->d_inode; | 858 | inode = nd->dentry->d_inode; |
847 | } else { | 859 | } else { |
848 | dput(nd->dentry); | 860 | dput(nd->dentry); |
861 | if (nd->mnt != next.mnt) | ||
862 | mntput(nd->mnt); | ||
849 | nd->mnt = next.mnt; | 863 | nd->mnt = next.mnt; |
850 | nd->dentry = next.dentry; | 864 | nd->dentry = next.dentry; |
851 | } | 865 | } |
@@ -885,6 +899,8 @@ return_base: | |||
885 | return 0; | 899 | return 0; |
886 | out_dput: | 900 | out_dput: |
887 | dput(next.dentry); | 901 | dput(next.dentry); |
902 | if (nd->mnt != next.mnt) | ||
903 | mntput(next.mnt); | ||
888 | break; | 904 | break; |
889 | } | 905 | } |
890 | path_release(nd); | 906 | path_release(nd); |
@@ -1398,7 +1414,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1398 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1414 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) |
1399 | { | 1415 | { |
1400 | int acc_mode, error = 0; | 1416 | int acc_mode, error = 0; |
1401 | struct dentry *dentry; | 1417 | struct path path; |
1402 | struct dentry *dir; | 1418 | struct dentry *dir; |
1403 | int count = 0; | 1419 | int count = 0; |
1404 | 1420 | ||
@@ -1442,23 +1458,24 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1442 | dir = nd->dentry; | 1458 | dir = nd->dentry; |
1443 | nd->flags &= ~LOOKUP_PARENT; | 1459 | nd->flags &= ~LOOKUP_PARENT; |
1444 | down(&dir->d_inode->i_sem); | 1460 | down(&dir->d_inode->i_sem); |
1445 | dentry = __lookup_hash(&nd->last, nd->dentry, nd); | 1461 | path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); |
1462 | path.mnt = nd->mnt; | ||
1446 | 1463 | ||
1447 | do_last: | 1464 | do_last: |
1448 | error = PTR_ERR(dentry); | 1465 | error = PTR_ERR(path.dentry); |
1449 | if (IS_ERR(dentry)) { | 1466 | if (IS_ERR(path.dentry)) { |
1450 | up(&dir->d_inode->i_sem); | 1467 | up(&dir->d_inode->i_sem); |
1451 | goto exit; | 1468 | goto exit; |
1452 | } | 1469 | } |
1453 | 1470 | ||
1454 | /* Negative dentry, just create the file */ | 1471 | /* Negative dentry, just create the file */ |
1455 | if (!dentry->d_inode) { | 1472 | if (!path.dentry->d_inode) { |
1456 | if (!IS_POSIXACL(dir->d_inode)) | 1473 | if (!IS_POSIXACL(dir->d_inode)) |
1457 | mode &= ~current->fs->umask; | 1474 | mode &= ~current->fs->umask; |
1458 | error = vfs_create(dir->d_inode, dentry, mode, nd); | 1475 | error = vfs_create(dir->d_inode, path.dentry, mode, nd); |
1459 | up(&dir->d_inode->i_sem); | 1476 | up(&dir->d_inode->i_sem); |
1460 | dput(nd->dentry); | 1477 | dput(nd->dentry); |
1461 | nd->dentry = dentry; | 1478 | nd->dentry = path.dentry; |
1462 | if (error) | 1479 | if (error) |
1463 | goto exit; | 1480 | goto exit; |
1464 | /* Don't check for write permission, don't truncate */ | 1481 | /* Don't check for write permission, don't truncate */ |
@@ -1476,22 +1493,24 @@ do_last: | |||
1476 | if (flag & O_EXCL) | 1493 | if (flag & O_EXCL) |
1477 | goto exit_dput; | 1494 | goto exit_dput; |
1478 | 1495 | ||
1479 | if (d_mountpoint(dentry)) { | 1496 | if (__follow_mount(&path)) { |
1480 | error = -ELOOP; | 1497 | error = -ELOOP; |
1481 | if (flag & O_NOFOLLOW) | 1498 | if (flag & O_NOFOLLOW) |
1482 | goto exit_dput; | 1499 | goto exit_dput; |
1483 | while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); | ||
1484 | } | 1500 | } |
1485 | error = -ENOENT; | 1501 | error = -ENOENT; |
1486 | if (!dentry->d_inode) | 1502 | if (!path.dentry->d_inode) |
1487 | goto exit_dput; | 1503 | goto exit_dput; |
1488 | if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) | 1504 | if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link) |
1489 | goto do_link; | 1505 | goto do_link; |
1490 | 1506 | ||
1491 | dput(nd->dentry); | 1507 | dput(nd->dentry); |
1492 | nd->dentry = dentry; | 1508 | nd->dentry = path.dentry; |
1509 | if (nd->mnt != path.mnt) | ||
1510 | mntput(nd->mnt); | ||
1511 | nd->mnt = path.mnt; | ||
1493 | error = -EISDIR; | 1512 | error = -EISDIR; |
1494 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) | 1513 | if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode)) |
1495 | goto exit; | 1514 | goto exit; |
1496 | ok: | 1515 | ok: |
1497 | error = may_open(nd, acc_mode, flag); | 1516 | error = may_open(nd, acc_mode, flag); |
@@ -1500,7 +1519,9 @@ ok: | |||
1500 | return 0; | 1519 | return 0; |
1501 | 1520 | ||
1502 | exit_dput: | 1521 | exit_dput: |
1503 | dput(dentry); | 1522 | dput(path.dentry); |
1523 | if (nd->mnt != path.mnt) | ||
1524 | mntput(path.mnt); | ||
1504 | exit: | 1525 | exit: |
1505 | path_release(nd); | 1526 | path_release(nd); |
1506 | return error; | 1527 | return error; |
@@ -1520,18 +1541,15 @@ do_link: | |||
1520 | * are done. Procfs-like symlinks just set LAST_BIND. | 1541 | * are done. Procfs-like symlinks just set LAST_BIND. |
1521 | */ | 1542 | */ |
1522 | nd->flags |= LOOKUP_PARENT; | 1543 | nd->flags |= LOOKUP_PARENT; |
1523 | error = security_inode_follow_link(dentry, nd); | 1544 | error = security_inode_follow_link(path.dentry, nd); |
1524 | if (error) | 1545 | if (error) |
1525 | goto exit_dput; | 1546 | goto exit_dput; |
1526 | error = __do_follow_link(dentry, nd); | 1547 | error = __do_follow_link(&path, nd); |
1527 | dput(dentry); | ||
1528 | if (error) | 1548 | if (error) |
1529 | return error; | 1549 | return error; |
1530 | nd->flags &= ~LOOKUP_PARENT; | 1550 | nd->flags &= ~LOOKUP_PARENT; |
1531 | if (nd->last_type == LAST_BIND) { | 1551 | if (nd->last_type == LAST_BIND) |
1532 | dentry = nd->dentry; | ||
1533 | goto ok; | 1552 | goto ok; |
1534 | } | ||
1535 | error = -EISDIR; | 1553 | error = -EISDIR; |
1536 | if (nd->last_type != LAST_NORM) | 1554 | if (nd->last_type != LAST_NORM) |
1537 | goto exit; | 1555 | goto exit; |
@@ -1546,7 +1564,8 @@ do_link: | |||
1546 | } | 1564 | } |
1547 | dir = nd->dentry; | 1565 | dir = nd->dentry; |
1548 | down(&dir->d_inode->i_sem); | 1566 | down(&dir->d_inode->i_sem); |
1549 | dentry = __lookup_hash(&nd->last, nd->dentry, nd); | 1567 | path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); |
1568 | path.mnt = nd->mnt; | ||
1550 | putname(nd->last.name); | 1569 | putname(nd->last.name); |
1551 | goto do_last; | 1570 | goto do_last; |
1552 | } | 1571 | } |