Re: [PATCH v3] readdir cf_nlink initialization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 18 Sep 2013 16:00:17 -0700
Jim McDonough <jmcd@xxxxxxxxx> wrote:

> One more try .  Trying to not trust non-unix servers when they are
> reporting zero without delete pending, or in the directory case, on
> querypathinfo, and never on readdir.  But only faking it on inode
> instantiation.
> 
> Also, this is finally for a recent kernel...
> 
> 
> --
>  fs/cifs/cifsglob.h |  1 +
>  fs/cifs/inode.c    | 41 +++++++++++++++++++++++++++++++++++------
>  fs/cifs/readdir.c  |  3 +++
>  3 files changed, 39 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 52ca861..750dbfa 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -1253,6 +1253,7 @@ struct dfs_info3_param {
>  #define CIFS_FATTR_DELETE_PENDING    0x2
>  #define CIFS_FATTR_NEED_REVAL        0x4
>  #define CIFS_FATTR_INO_COLLISION    0x8
> +#define CIFS_FATTR_UNKNOWN_NLINK    0x10
> 
>  struct cifs_fattr {
>      u32        cf_flags;
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 449b6cf..1d7bbb9 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -120,6 +120,30 @@ cifs_revalidate_cache(struct inode *inode, struct
> cifs_fattr *fattr)
>      cifs_i->invalid_mapping = true;
>  }
> 
> +/* copy nlink to the inode, unless it wasn't provided.  Provide
> +   sane values if we don't have an existing one and none was provided */
> +static void
> +cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
> +{
> +    /* if we're in a situation where we can't trust what we
> +       got from the server (readdir, some non-unix cases)
> +       fake reasonable values
> +    */

Nit: best to use kernel-style comments. Also, this patch appears to be
whitespace-damaged.

> +    if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
> +        /* only provide fake values on a new inode */
> +        if (inode->i_state & I_NEW) {
> +            if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
> +                set_nlink(inode, 2);
> +            else
> +                set_nlink(inode, 1);
> +        }
> +        return;
> +    }
> +
> +    /* we trust the server, so update it */
> +    set_nlink(inode, fattr->cf_nlink);
> +}
> +
>  /* populate an inode with info from a cifs_fattr struct */
>  void
>  cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
> @@ -134,7 +158,7 @@ cifs_fattr_to_inode(struct inode *inode, struct
> cifs_fattr *fattr)
>      inode->i_mtime = fattr->cf_mtime;
>      inode->i_ctime = fattr->cf_ctime;
>      inode->i_rdev = fattr->cf_rdev;
> -    set_nlink(inode, fattr->cf_nlink);
> +    cifs_nlink_fattr_to_inode(inode, fattr);
>      inode->i_uid = fattr->cf_uid;
>      inode->i_gid = fattr->cf_gid;
> 
> @@ -541,6 +565,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr,
> FILE_ALL_INFO *info,
>      fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
>      fattr->cf_createtime = le64_to_cpu(info->CreationTime);
> 
> +    fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
>      if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
>          fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
>          fattr->cf_dtype = DT_DIR;
> @@ -548,7 +573,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr,
> FILE_ALL_INFO *info,
>           * Server can return wrong NumberOfLinks value for directories
>           * when Unix extensions are disabled - fake it.
>           */
> -        fattr->cf_nlink = 2;
> +        if (!tcon->unix_ext)
> +            fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
>      } else {
>          fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
>          fattr->cf_dtype = DT_REG;
> @@ -557,11 +583,14 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr,
> FILE_ALL_INFO *info,
>          if (fattr->cf_cifsattrs & ATTR_READONLY)
>              fattr->cf_mode &= ~(S_IWUGO);
> 
> -        fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
> -        if (fattr->cf_nlink < 1) {
> -            cifs_dbg(1, "replacing bogus file nlink value %u\n",
> +        /* Don't accept zero nlink from non-unix servers unless
> +           delete is pending.  Instead mark it as unknown.
> +        */
> +        if ((fattr->cf_nlink < 1) && (!tcon->unix_ext) &&
> +            (!info->DeletePending)) {

Probably don't need all of the extra parens in the above conditional,
and the indentation below looks funny. Some of that might be the
tabs-to-spaces conversion that seems to have occured here though.

> +            cifs_dbg(1, "bogus file nlink value %u\n",
>                  fattr->cf_nlink);
> -            fattr->cf_nlink = 1;
> +            fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
>          }
>      }
> 
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index 69d2c82..b1f67dc 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
> @@ -177,6 +177,9 @@ cifs_fill_common_info(struct cifs_fattr *fattr,
> struct cifs_sb_info *cifs_sb)
>          fattr->cf_dtype = DT_REG;
>      }
> 
> +    /* non-unix readdir doesn't provide nlink */
> +    fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
> +
>      if (fattr->cf_cifsattrs & ATTR_READONLY)
>          fattr->cf_mode &= ~S_IWUGO;
> 

Nice work! The logic looks correct. It just needs a little bit of style
cleanup and to be sent in a way that hasn't converted tabs to spaces.

You can add this to the final patch:

Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux