[linux-cifs-client] [PATCH] cifs: guard against hardlinking directories

Steve French smfrench at gmail.com
Fri May 7 08:34:24 MDT 2010


I have reviewed this and this looks good - just need a tested by or reviewed by.

On Fri, May 7, 2010 at 9:03 AM, Jeff Layton <jlayton at redhat.com> wrote:
> When we made serverino the default, we trusted that the field sent by the
> server in the "uniqueid" field was actually unique. It turns out that it
> isn't reliably so.
>
> Samba, in particular, will just put the st_ino in the uniqueid field when
> unix extensions are enabled. When a share spans multiple filesystems, it's
> quite possible that there will be collisions. This is a server bug, but
> when the inodes in question are a directory (as is often the case) and
> there is a collision with the root inode of the mount, the result is a
> kernel panic on umount.
>
> Fix this by checking explicitly for directory inodes with the same
> uniqueid. If that is the case, then we can assume that using server inode
> numbers will be a problem and that they should be disabled.
>
> Signed-off-by: Jeff Layton <jlayton at redhat.com>
> ---
>  fs/cifs/cifsglob.h |    1 +
>  fs/cifs/inode.c    |   21 +++++++++++++++++++--
>  2 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index ecf0ffb..0c2fd17 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -502,6 +502,7 @@ struct dfs_info3_param {
>  #define CIFS_FATTR_DFS_REFERRAL                0x1
>  #define CIFS_FATTR_DELETE_PENDING      0x2
>  #define CIFS_FATTR_NEED_REVAL          0x4
> +#define CIFS_FATTR_INO_COLLISION       0x8
>
>  struct cifs_fattr {
>        u32             cf_flags;
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index ee35c97..fb20f11 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -714,6 +714,16 @@ cifs_find_inode(struct inode *inode, void *opaque)
>        if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
>                return 0;
>
> +       /*
> +        * uh oh -- it's a directory. We can't use it since hardlinked dirs are
> +        * verboten. Disable serverino and return it as if it were found, the
> +        * caller can discard it, generate a uniqueid and retry the find
> +        */
> +       if (S_ISDIR(inode->i_mode)) {
> +               fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
> +               cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
> +       }
> +
>        return 1;
>  }
>
> @@ -733,15 +743,22 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
>        unsigned long hash;
>        struct inode *inode;
>
> +retry_iget5_locked:
>        cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
>
>        /* hash down to 32-bits on 32-bit arch */
>        hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
>
>        inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
> -
> -       /* we have fattrs in hand, update the inode */
>        if (inode) {
> +               /* was there a problematic inode number collision? */
> +               if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
> +                       iput(inode);
> +                       fattr->cf_uniqueid = iunique(sb, ROOT_I);
> +                       fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
> +                       goto retry_iget5_locked;
> +               }
> +
>                cifs_fattr_to_inode(inode, fattr);
>                if (sb->s_flags & MS_NOATIME)
>                        inode->i_flags |= S_NOATIME | S_NOCMTIME;
> --
> 1.7.0.1
>
>



-- 
Thanks,

Steve


More information about the linux-cifs-client mailing list