All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v3] readdir cf_nlink initialization
@ 2013-09-18 23:00 Jim McDonough
       [not found] ` <CAFneQccAzKRE1O31528S4T4rsHZ7Wn+acV6Cmr1+QAwd+JmNPg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Jim McDonough @ 2013-09-18 23:00 UTC (permalink / raw)
  To: Jeff Layton
  Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Disseldorp,
	Jeremy Allison, Shirish Pargaonkar

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
+    */
+    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)) {
+            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;

-- 
1.8.1.4




-- 
Jim McDonough
Samba Team
SUSE labs
jmcd at samba dot org
jmcd at themcdonoughs dot org

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v3] readdir cf_nlink initialization
       [not found] ` <CAFneQccAzKRE1O31528S4T4rsHZ7Wn+acV6Cmr1+QAwd+JmNPg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2013-09-19 12:18   ` Jeff Layton
       [not found]     ` <20130919081808.7aa63e90-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Jeff Layton @ 2013-09-19 12:18 UTC (permalink / raw)
  To: Jim McDonough
  Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Disseldorp,
	Jeremy Allison, Shirish Pargaonkar

On Wed, 18 Sep 2013 16:00:17 -0700
Jim McDonough <jmcd-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> 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-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] readdir cf_nlink initialization
       [not found]     ` <20130919081808.7aa63e90-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2013-09-19 17:24       ` Jim McDonough
       [not found]         ` <523B3358.2070802-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Jim McDonough @ 2013-09-19 17:24 UTC (permalink / raw)
  To: Jeff Layton
  Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Disseldorp,
	Jeremy Allison, Shirish Pargaonkar

[-- Attachment #1: Type: text/plain, Size: 4397 bytes --]

Ok, hopefully this is it.  Without cut/paste whitespace and all....

From 341fa690befb7d6da51a0775914aab19e9059c57 Mon Sep 17 00:00:00 2001
From: Jim McDonough <jmcd-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
Date: Thu, 19 Sep 2013 17:22:00 -0700
Subject: Provide sane values for nlink

Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 fs/cifs/cifsglob.h |  1 +
 fs/cifs/inode.c    | 42 ++++++++++++++++++++++++++++++++++++------
 fs/cifs/readdir.c  |  3 +++
 3 files changed, 40 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..14136dc 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -120,6 +120,31 @@ 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
+	 */
+	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 +159,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 +566,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 +574,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 +584,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) {
+			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;

-- 
1.8.1.4



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] readdir cf_nlink initialization
       [not found]         ` <523B3358.2070802-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2013-09-19 17:39           ` Jim McDonough
       [not found]             ` <523B36CF.5020700-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Jim McDonough @ 2013-09-19 17:39 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
  Cc: Jeff Layton, David Disseldorp, Jeremy Allison, Shirish Pargaonkar

[-- Attachment #1: Type: text/plain, Size: 4456 bytes --]

Sigh, more comment fixup...

From b575840809eb8fdad7c595202300414e25b7d286 Mon Sep 17 00:00:00 2001
From: Jim McDonough <jmcd-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
Date: Thu, 19 Sep 2013 17:22:00 -0700
Subject: Provide sane values for nlink

Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Reviewed-by: David Disseldorp <ddiss-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
 fs/cifs/cifsglob.h |  1 +
 fs/cifs/inode.c    | 45 +++++++++++++++++++++++++++++++++++++++------
 fs/cifs/readdir.c  |  3 +++
 3 files changed, 43 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..b2f4831 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -120,6 +120,33 @@ 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
+	 */
+	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 +161,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 +568,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 +576,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 +586,15 @@ 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) {
+			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;

-- 
1.8.1.4



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v4] readdir cf_nlink initialization
       [not found]             ` <523B36CF.5020700-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2013-09-21 15:49               ` Steve French
  0 siblings, 0 replies; 5+ messages in thread
From: Steve French @ 2013-09-21 15:49 UTC (permalink / raw)
  To: James McDonough
  Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Jeff Layton,
	David Disseldorp, Jeremy Allison, Shirish Pargaonkar

Merged into cifs-2.6.git, but required fixup because the patch was
based off an earlier kernel and did not merge cleanly (conflicted with
a small DFS fix in 3.11).   Also when you respun it you left off the
patch description, so I took it from parts of the earlier patch.

On Thu, Sep 19, 2013 at 12:39 PM, Jim McDonough <jmcd-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> Sigh, more comment fixup...
>
> From b575840809eb8fdad7c595202300414e25b7d286 Mon Sep 17 00:00:00 2001
> From: Jim McDonough <jmcd-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> Date: Thu, 19 Sep 2013 17:22:00 -0700
> Subject: Provide sane values for nlink
>
> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Reviewed-by: David Disseldorp <ddiss-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/cifsglob.h |  1 +
>  fs/cifs/inode.c    | 45 +++++++++++++++++++++++++++++++++++++++------
>  fs/cifs/readdir.c  |  3 +++
>  3 files changed, 43 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..b2f4831 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -120,6 +120,33 @@ 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
> +        */
> +       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 +161,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 +568,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 +576,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 +586,15 @@ 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) {
> +                       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;
>
> --
> 1.8.1.4
>
>



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-09-21 15:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-18 23:00 [PATCH v3] readdir cf_nlink initialization Jim McDonough
     [not found] ` <CAFneQccAzKRE1O31528S4T4rsHZ7Wn+acV6Cmr1+QAwd+JmNPg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-09-19 12:18   ` Jeff Layton
     [not found]     ` <20130919081808.7aa63e90-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2013-09-19 17:24       ` [PATCH v4] " Jim McDonough
     [not found]         ` <523B3358.2070802-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2013-09-19 17:39           ` Jim McDonough
     [not found]             ` <523B36CF.5020700-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2013-09-21 15:49               ` Steve French

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.