diff mbox

[SMB3] Fake an inode number when server returns inode number zero for the root

Message ID CAH2r5mtezqedoqK_GAYGwyujk1dXFdVyjQ50OaJfEJtUi5uEpw@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve French April 1, 2018, 9:49 p.m. UTC
Slightly updated version (shorter by a couple lines)

On Sat, Mar 31, 2018 at 6:17 PM, Steve French <smfrench@gmail.com> wrote:
> Some servers return inode number zero for the root (ok for all other
> inodes), if so
> we need to create a non-zero hash instead for it and use that.
>
>
>
> --
> Thanks,
>
> Steve

Comments

Pavel Shilovsky April 2, 2018, 5:43 p.m. UTC | #1
2018-04-01 14:49 GMT-07:00 Steve French <smfrench@gmail.com>:
> Slightly updated version (shorter by a couple lines)
>
> On Sat, Mar 31, 2018 at 6:17 PM, Steve French <smfrench@gmail.com> wrote:
>> Some servers return inode number zero for the root (ok for all other
>> inodes), if so
>> we need to create a non-zero hash instead for it and use that.
>>
>>
>>
>> --
>> Thanks,
>>
>> Steve
>
>
>
> --
> Thanks,
>
> Steve

Please include the prefix "CIFS:" to patch names, [CIFS] is being
omitted in the title when you apply a patch to git.

Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>

--
Best regards,
Pavel Shilovsky
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve French April 2, 2018, 6:03 p.m. UTC | #2
On Mon, Apr 2, 2018 at 12:43 PM, Pavel Shilovsky <piastryyy@gmail.com> wrote:
> 2018-04-01 14:49 GMT-07:00 Steve French <smfrench@gmail.com>:
>> Slightly updated version (shorter by a couple lines)
>>
>> On Sat, Mar 31, 2018 at 6:17 PM, Steve French <smfrench@gmail.com> wrote:
>>> Some servers return inode number zero for the root (ok for all other
>>> inodes), if so
>>> we need to create a non-zero hash instead for it and use that.
>>>
<...>
> Please include the prefix "CIFS:" to patch names, [CIFS] is being
> omitted in the title when you apply a patch to git.
>
> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
>
> --
> Best regards,
> Pavel Shilovsky

Yep - you are right.  It was getting stripped out.  Fixed and added
your reviewed by.
diff mbox

Patch

From 0bfedb011d647bb044826f878c711aee8ddb26b7 Mon Sep 17 00:00:00 2001
From: Steve French <stfrench@microsoft.com>
Date: Sat, 31 Mar 2018 18:13:38 -0500
Subject: [PATCH] Fix root directory when server returns inode number of zero

Some servers return inode number zero for the root directory, which
causes ls to display incorrect data (missing "." and "..").

If the server returns zero for the inode number of the root directory,
fake an inode number for it.

Signed-off-by: Steve French <smfrench@gmail.com>
---
 fs/cifs/cifsglob.h |  1 +
 fs/cifs/inode.c    | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3e3f86841372..2282562e78a1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1470,6 +1470,7 @@  struct dfs_info3_param {
 #define CIFS_FATTR_NEED_REVAL		0x4
 #define CIFS_FATTR_INO_COLLISION	0x8
 #define CIFS_FATTR_UNKNOWN_NLINK	0x10
+#define CIFS_FATTR_FAKE_ROOT_INO	0x20
 
 struct cifs_fattr {
 	u32		cf_flags;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index c98a852180b1..6718158505ea 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -707,6 +707,18 @@  cifs_get_file_info(struct file *filp)
 	return rc;
 }
 
+/* Simple function to return a 64 bit hash of string.  Rarely called */
+static __u64 simple_hashstr(const char *str)
+{
+	const __u64 hash_mult =  1125899906842597; /* a big enough prime */
+	__u64 hash = 0;
+
+	while (*str)
+		hash = (hash + (__u64) *str++) * hash_mult;
+
+	return hash;
+}
+
 int
 cifs_get_inode_info(struct inode **inode, const char *full_path,
 		    FILE_ALL_INFO *data, struct super_block *sb, int xid,
@@ -816,6 +828,14 @@  cifs_get_inode_info(struct inode **inode, const char *full_path,
 						 tmprc);
 					fattr.cf_uniqueid = iunique(sb, ROOT_I);
 					cifs_autodisable_serverino(cifs_sb);
+				} else if ((fattr.cf_uniqueid == 0) &&
+						strlen(full_path) == 0) {
+					/* some servers ret bad root ino ie 0 */
+					cifs_dbg(FYI, "Invalid (0) inodenum\n");
+					fattr.cf_flags |=
+						CIFS_FATTR_FAKE_ROOT_INO;
+					fattr.cf_uniqueid =
+						simple_hashstr(tcon->treeName);
 				}
 			}
 		} else
@@ -832,6 +852,16 @@  cifs_get_inode_info(struct inode **inode, const char *full_path,
 				&fattr.cf_uniqueid, data);
 			if (tmprc)
 				fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+			else if ((fattr.cf_uniqueid == 0) &&
+					strlen(full_path) == 0) {
+				/*
+				 * Reuse existing root inode num since
+				 * inum zero for root causes ls of . and .. to
+				 * not be returned
+				 */
+				cifs_dbg(FYI, "Srv ret 0 inode num for root\n");
+				fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+			}
 		} else
 			fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
 	}
@@ -893,6 +923,9 @@  cifs_get_inode_info(struct inode **inode, const char *full_path,
 	}
 
 cgii_exit:
+	if ((*inode) && ((*inode)->i_ino == 0))
+		cifs_dbg(FYI, "inode number of zero returned\n");
+
 	kfree(buf);
 	cifs_put_tlink(tlink);
 	return rc;
-- 
2.14.1