diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 21 | ||||
| -rw-r--r-- | fs/namei.c | 6 |
3 files changed, 24 insertions, 4 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ecf0ffbe2b64..0c2fd17439c8 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -502,6 +502,7 @@ struct dfs_info3_param { | |||
| 502 | #define CIFS_FATTR_DFS_REFERRAL 0x1 | 502 | #define CIFS_FATTR_DFS_REFERRAL 0x1 |
| 503 | #define CIFS_FATTR_DELETE_PENDING 0x2 | 503 | #define CIFS_FATTR_DELETE_PENDING 0x2 |
| 504 | #define CIFS_FATTR_NEED_REVAL 0x4 | 504 | #define CIFS_FATTR_NEED_REVAL 0x4 |
| 505 | #define CIFS_FATTR_INO_COLLISION 0x8 | ||
| 505 | 506 | ||
| 506 | struct cifs_fattr { | 507 | struct cifs_fattr { |
| 507 | u32 cf_flags; | 508 | u32 cf_flags; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 35ec11716213..29b9ea244c81 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -715,6 +715,16 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
| 715 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 715 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
| 716 | return 0; | 716 | return 0; |
| 717 | 717 | ||
| 718 | /* | ||
| 719 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | ||
| 720 | * verboten. Disable serverino and return it as if it were found, the | ||
| 721 | * caller can discard it, generate a uniqueid and retry the find | ||
| 722 | */ | ||
| 723 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) { | ||
| 724 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; | ||
| 725 | cifs_autodisable_serverino(CIFS_SB(inode->i_sb)); | ||
| 726 | } | ||
| 727 | |||
| 718 | return 1; | 728 | return 1; |
| 719 | } | 729 | } |
| 720 | 730 | ||
| @@ -734,15 +744,22 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) | |||
| 734 | unsigned long hash; | 744 | unsigned long hash; |
| 735 | struct inode *inode; | 745 | struct inode *inode; |
| 736 | 746 | ||
| 747 | retry_iget5_locked: | ||
| 737 | cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid)); | 748 | cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid)); |
| 738 | 749 | ||
| 739 | /* hash down to 32-bits on 32-bit arch */ | 750 | /* hash down to 32-bits on 32-bit arch */ |
| 740 | hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); | 751 | hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); |
| 741 | 752 | ||
| 742 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); | 753 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); |
| 743 | |||
| 744 | /* we have fattrs in hand, update the inode */ | ||
| 745 | if (inode) { | 754 | if (inode) { |
| 755 | /* was there a problematic inode number collision? */ | ||
| 756 | if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { | ||
| 757 | iput(inode); | ||
| 758 | fattr->cf_uniqueid = iunique(sb, ROOT_I); | ||
| 759 | fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; | ||
| 760 | goto retry_iget5_locked; | ||
| 761 | } | ||
| 762 | |||
| 746 | cifs_fattr_to_inode(inode, fattr); | 763 | cifs_fattr_to_inode(inode, fattr); |
| 747 | if (sb->s_flags & MS_NOATIME) | 764 | if (sb->s_flags & MS_NOATIME) |
| 748 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 765 | inode->i_flags |= S_NOATIME | S_NOCMTIME; |
diff --git a/fs/namei.c b/fs/namei.c index a7dce91a7e42..16df7277a92e 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1641,7 +1641,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
| 1641 | if (nd->last.name[nd->last.len]) { | 1641 | if (nd->last.name[nd->last.len]) { |
| 1642 | if (open_flag & O_CREAT) | 1642 | if (open_flag & O_CREAT) |
| 1643 | goto exit; | 1643 | goto exit; |
| 1644 | nd->flags |= LOOKUP_DIRECTORY; | 1644 | nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW; |
| 1645 | } | 1645 | } |
| 1646 | 1646 | ||
| 1647 | /* just plain open? */ | 1647 | /* just plain open? */ |
| @@ -1830,6 +1830,8 @@ reval: | |||
| 1830 | } | 1830 | } |
| 1831 | if (open_flag & O_DIRECTORY) | 1831 | if (open_flag & O_DIRECTORY) |
| 1832 | nd.flags |= LOOKUP_DIRECTORY; | 1832 | nd.flags |= LOOKUP_DIRECTORY; |
| 1833 | if (!(open_flag & O_NOFOLLOW)) | ||
| 1834 | nd.flags |= LOOKUP_FOLLOW; | ||
| 1833 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1835 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
| 1834 | while (unlikely(!filp)) { /* trailing symlink */ | 1836 | while (unlikely(!filp)) { /* trailing symlink */ |
| 1835 | struct path holder; | 1837 | struct path holder; |
| @@ -1837,7 +1839,7 @@ reval: | |||
| 1837 | void *cookie; | 1839 | void *cookie; |
| 1838 | error = -ELOOP; | 1840 | error = -ELOOP; |
| 1839 | /* S_ISDIR part is a temporary automount kludge */ | 1841 | /* S_ISDIR part is a temporary automount kludge */ |
| 1840 | if ((open_flag & O_NOFOLLOW) && !S_ISDIR(inode->i_mode)) | 1842 | if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode)) |
| 1841 | goto exit_dput; | 1843 | goto exit_dput; |
| 1842 | if (count++ == 32) | 1844 | if (count++ == 32) |
| 1843 | goto exit_dput; | 1845 | goto exit_dput; |
