All of lore.kernel.org
 help / color / mirror / Atom feed
* mount.cifs with "prefixpath" option getting NT_STATUS_ACCESS_DENIED
@ 2011-08-22 17:30 Rafael Ganascim
       [not found] ` <CAD4ZOMwcYFut0o8Krw-Z+tiGwz9VNvy4jRvwMcXv42P60pJxbg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 5+ messages in thread
From: Rafael Ganascim @ 2011-08-22 17:30 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

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

Hi,

I think that this problem is related to:

http://article.gmane.org/gmane.linux.kernel.cifs/3878


I have this fileserver structure:
 - complete path: //fileserver-la-01/ti$/geral/
 - //fileserver-la-01/ti$: in this parent dir, my user don't have
permission to access


Using the kernel version 2.6.38 the mount reports:

# mount -v /mnt/xxxx/latigeral/
parsing options: rw,credentials=/etc/credentials,uid=1000

mount.cifs kernel mount options
unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/
#


Using the kernel 3.0.2:

# mount -v /mnt/xxxx/latigeral
parsing options: rw,credentials=/etc/credentials,uid=1000

mount.cifs kernel mount options
unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/
mount error(13): Permission denied
Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)
#

The cifsFYI messages are in the attachments, cifsFYI.txt.

To workaround this problem (in my box), I had set the 'full_path'
(from prefixpath) in the call to cifs_get_inode_info in the function
cifs_root_iget (~ inode.c:888), if the prefixpath isn't null. This
worked for me, but it's bad solution, I think (i'm not a programmer :(
).

What do you think about this problem? There are a 'good' solution for it?


Thanks,
--

Rafael Ganascim

[-- Attachment #2: cifsFYI.txt --]
[-- Type: text/plain, Size: 9410 bytes --]

Using the kernel version 2.6.38 the mount reports:

# mount -v /mnt/xxxx/latigeral/
parsing options: rw,credentials=/etc/credentials,uid=1000

mount.cifs kernel mount options unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/ 
#

# dmesg
...
fs/cifs/cifsfs.c: Devname: //fileserver-la-01/ti$/geral/ flags: 64 
fs/cifs/connect.c: CIFS VFS: in cifs_mount as Xid: 27 with uid: 0
fs/cifs/connect.c: prefix path /geral/
fs/cifs/connect.c: Username: xxxx
fs/cifs/connect.c: UNC: \\fileserver-la-01\ti$ ip: 172.25.4.13
fs/cifs/connect.c: Socket created
fs/cifs/connect.c: sndbuf 16384 rcvbuf 87380 rcvtimeo 0x1b58
fs/cifs/connect.c: CIFS VFS: in cifs_get_smb_ses as Xid: 28 with uid: 0
fs/cifs/connect.c: Existing smb sess not found
fs/cifs/cifssmb.c: secFlags 0x7
fs/cifs/transport.c: For smb_command 114
fs/cifs/transport.c: Sending smb:  total_len 73
fs/cifs/connect.c: Demultiplex PID: 3327
fs/cifs/connect.c: rfc1002 length 0x79
fs/cifs/transport.c: sync_mid_result: cmd=114 mid=1 state=4
fs/cifs/cifssmb.c: Dialect: 2
fs/cifs/cifssmb.c: negprot rc 0
fs/cifs/connect.c: Security Mode: 0x3 Capabilities: 0x1f3fc TimeAdjust: 10800
fs/cifs/sess.c: sess setup type 1
fs/cifs/transport.c: For smb_command 115
fs/cifs/transport.c: Sending smb:  total_len 252
fs/cifs/connect.c: rfc1002 length 0xd1
fs/cifs/transport.c: sync_mid_result: cmd=115 mid=2 state=4
fs/cifs/misc.c: Null buffer passed to cifs_small_buf_release
fs/cifs/sess.c: UID = 6145 
fs/cifs/sess.c: bleft 163
fs/cifs/sess.c: serverOS=Windows Server 2008 R2 Standard 7600
fs/cifs/sess.c: serverNOS=Windows Server 2008 R2 Standard 6.1
fs/cifs/sess.c: serverDomain=xxxx-BR
fs/cifs/sess.c: ssetup freeing small buf f5013d40
fs/cifs/connect.c: CIFS Session Established successfully
fs/cifs/connect.c: CIFS VFS: leaving cifs_get_smb_ses (xid = 28) rc = 0
fs/cifs/connect.c: file mode: 0x1ed  dir mode: 0x1ed
fs/cifs/connect.c: CIFS VFS: in cifs_get_tcon as Xid: 29 with uid: 0
fs/cifs/transport.c: For smb_command 117
fs/cifs/transport.c: Sending smb:  total_len 100
fs/cifs/connect.c: rfc1002 length 0x42
fs/cifs/transport.c: sync_mid_result: cmd=117 mid=3 state=4
fs/cifs/connect.c: disk share connection
fs/cifs/connect.c: nativeFileSystem=NTFS
fs/cifs/connect.c: Tcon flags: 0x1 
fs/cifs/connect.c: CIFS VFS: leaving cifs_get_tcon (xid = 29) rc = 0
fs/cifs/connect.c: CIFS Tcon rc = 0
fs/cifs/cifssmb.c: In QFSDeviceInfo
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 72
fs/cifs/connect.c: rfc1002 length 0x44
fs/cifs/transport.c: sync_mid_result: cmd=50 mid=4 state=4
fs/cifs/cifssmb.c: In QFSAttributeInfo
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 72
fs/cifs/connect.c: rfc1002 length 0x50
fs/cifs/transport.c: sync_mid_result: cmd=50 mid=5 state=4
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 92
fs/cifs/connect.c: rfc1002 length 0xbe
fs/cifs/transport.c: sync_mid_result: cmd=50 mid=6 state=4
fs/cifs/connect.c: CIFS VFS: leaving cifs_mount (xid = 27) rc = 0
fs/cifs/inode.c: CIFS VFS: in cifs_root_iget as Xid: 30 with uid: 0
fs/cifs/inode.c: Getting info on \geral\
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 92
fs/cifs/connect.c: rfc1002 length 0xbe
fs/cifs/transport.c: sync_mid_result: cmd=50 mid=7 state=4
fs/cifs/cifssmb.c: In GetSrvInodeNum for \geral\
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 92
fs/cifs/connect.c: rfc1002 length 0x48
fs/cifs/transport.c: sync_mid_result: cmd=50 mid=8 state=4
fs/cifs/inode.c: looking for uniqueid=1970324837000647
fs/cifs/inode.c: cifs_revalidate_cache: revalidating inode 1970324837000647
fs/cifs/inode.c: cifs_revalidate_cache: inode 1970324837000647 is new
fs/cifs/inode.c: inode 0xe987c374 old_time=0 new_time=-121655
...

Using the kernel 3.0.2:

# mount -v /mnt/xxxx/latigeral
parsing options: rw,credentials=/etc/credentials,uid=1000

mount.cifs kernel mount options unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/ 
mount error(13): Permission denied
Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)
#

# dmesg
...
fs/cifs/cifsfs.c: Devname: //fileserver-la-01/ti$/geral/ flags: 64 
fs/cifs/connect.c: prefix path /geral/
fs/cifs/connect.c: Username: xxxxxx
fs/cifs/connect.c: file mode: 0x1ed  dir mode: 0x1ed
fs/cifs/connect.c: CIFS VFS: in cifs_mount as Xid: 0 with uid: 0
fs/cifs/connect.c: UNC: \\fileserver-la-01\ti$ ip: 172.25.4.13
fs/cifs/netmisc.c: address conversion returned 1 for 172.25.4.13
fs/cifs/connect.c: Socket created
fs/cifs/connect.c: sndbuf 16384 rcvbuf 87380 rcvtimeo 0x6d6
fs/cifs/connect.c: CIFS VFS: in cifs_get_smb_ses as Xid: 1 with uid: 0
fs/cifs/connect.c: Existing smb sess not found
CIFS VFS: default security mechanism requested.  The default security mechanism will be upgraded from ntlm to ntlmv2 in kernel release 3.1
fs/cifs/cifssmb.c: secFlags 0x7
fs/cifs/transport.c: For smb_command 114
fs/cifs/transport.c: Sending smb:  total_len 82
fs/cifs/connect.c: Demultiplex PID: 4435
fs/cifs/connect.c: rfc1002 length 0x79
fs/cifs/transport.c: cifs_sync_mid_result: cmd=114 mid=1 state=4
fs/cifs/cifssmb.c: Dialect: 2
fs/cifs/cifssmb.c: Max buf = 16472
fs/cifs/cifssmb.c: negprot rc 0
fs/cifs/connect.c: Security Mode: 0x3 Capabilities: 0x1f3fc TimeAdjust: 10800
fs/cifs/sess.c: sess setup type 1
fs/cifs/transport.c: For smb_command 115
fs/cifs/transport.c: Sending smb:  total_len 254
fs/cifs/connect.c: rfc1002 length 0xd1
fs/cifs/transport.c: cifs_sync_mid_result: cmd=115 mid=2 state=4
fs/cifs/misc.c: Null buffer passed to cifs_small_buf_release
fs/cifs/sess.c: UID = 2048 
fs/cifs/sess.c: bleft 163
fs/cifs/sess.c: serverOS=Windows Server 2008 R2 Standard 7600
fs/cifs/sess.c: serverNOS=Windows Server 2008 R2 Standard 6.1
fs/cifs/sess.c: serverDomain=XXXXX-BR
fs/cifs/sess.c: ssetup freeing small buf f5426f40
fs/cifs/connect.c: CIFS Session Established successfully
fs/cifs/connect.c: CIFS VFS: leaving cifs_get_smb_ses (xid = 1) rc = 0
fs/cifs/connect.c: CIFS VFS: in cifs_get_tcon as Xid: 2 with uid: 0
fs/cifs/transport.c: For smb_command 117
fs/cifs/transport.c: Sending smb:  total_len 100
fs/cifs/connect.c: rfc1002 length 0x42
fs/cifs/transport.c: cifs_sync_mid_result: cmd=117 mid=3 state=4
fs/cifs/connect.c: disk share connection
fs/cifs/connect.c: nativeFileSystem=NTFS
fs/cifs/connect.c: Tcon flags: 0x1 
fs/cifs/connect.c: CIFS VFS: leaving cifs_get_tcon (xid = 2) rc = 0
fs/cifs/connect.c: CIFS Tcon rc = 0
fs/cifs/cifssmb.c: In QFSDeviceInfo
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 72
fs/cifs/connect.c: rfc1002 length 0x44
fs/cifs/transport.c: cifs_sync_mid_result: cmd=50 mid=4 state=4
fs/cifs/cifssmb.c: In QFSAttributeInfo
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 72
fs/cifs/connect.c: rfc1002 length 0x50
fs/cifs/transport.c: cifs_sync_mid_result: cmd=50 mid=5 state=4
fs/cifs/connect.c: build_unc_path_to_root: full_path=\\fileserver-la-01\ti$\geral\
fs/cifs/transport.c: For smb_command 117
fs/cifs/transport.c: Sending smb:  total_len 92
fs/cifs/connect.c: rfc1002 length 0x3c
fs/cifs/transport.c: cifs_sync_mid_result: cmd=117 mid=6 state=4
fs/cifs/connect.c: CIFS Tcon rc = 0 ipc_tid = 2049
fs/cifs/cifssmb.c: In GetDFSRefer the path \fileserver-la-01\ti$
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 118
fs/cifs/connect.c: rfc1002 length 0x27
fs/cifs/connect.c: invalid transact2 word count
fs/cifs/transport.c: cifs_sync_mid_result: cmd=50 mid=7 state=4
fs/cifs/netmisc.c: Mapping smb error code 0xc0000225 to POSIX err -5
fs/cifs/cifssmb.c: Send error in GetDFSRefer = -5
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 92
fs/cifs/connect.c: rfc1002 length 0xbe
fs/cifs/transport.c: cifs_sync_mid_result: cmd=50 mid=8 state=4
fs/cifs/connect.c: CIFS VFS: leaving cifs_mount (xid = 0) rc = 0
fs/cifs/inode.c: CIFS VFS: in cifs_root_iget as Xid: 3 with uid: 0
fs/cifs/inode.c: Getting info on 
fs/cifs/transport.c: For smb_command 50
fs/cifs/transport.c: Sending smb:  total_len 78
fs/cifs/connect.c: rfc1002 length 0x27
fs/cifs/connect.c: invalid transact2 word count
fs/cifs/transport.c: cifs_sync_mid_result: cmd=50 mid=9 state=4
fs/cifs/netmisc.c: Mapping smb error code 0xc0000022 to POSIX err -13
fs/cifs/cifssmb.c: Send error in QPathInfo = -13
CIFS VFS: cifs_read_super: get root inode failed
fs/cifs/connect.c: cifs_put_tcon: tc_count=1

fs/cifs/connect.c: CIFS VFS: in cifs_put_tcon as Xid: 4 with uid: 0
fs/cifs/cifssmb.c: In tree disconnect
fs/cifs/transport.c: For smb_command 113
fs/cifs/transport.c: Sending smb:  total_len 39
fs/cifs/connect.c: rfc1002 length 0x27
fs/cifs/transport.c: cifs_sync_mid_result: cmd=113 mid=10 state=4
fs/cifs/transport.c: SendRcvNoRsp flags 64 rc 0
fs/cifs/connect.c: cifs_put_smb_ses: ses_count=1

fs/cifs/connect.c: CIFS VFS: in cifs_put_smb_ses as Xid: 5 with uid: 0
fs/cifs/cifssmb.c: In SMBLogoff for session disconnect
fs/cifs/transport.c: For smb_command 116
fs/cifs/transport.c: Sending smb:  total_len 43
fs/cifs/connect.c: rfc1002 length 0x2b
fs/cifs/transport.c: cifs_sync_mid_result: cmd=116 mid=11 state=4
fs/cifs/transport.c: SendRcvNoRsp flags 64 rc 0
...


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

* [PATCH] CIFS: Fix NT_STATUS_ACCESS for moutn with prefixpath option
       [not found] ` <CAD4ZOMwcYFut0o8Krw-Z+tiGwz9VNvy4jRvwMcXv42P60pJxbg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-08-25 21:04   ` Pavel Shilovsky
  2014-04-23 19:27     ` Ryan Johnson
  2011-08-25 21:08   ` mount.cifs with "prefixpath" option getting NT_STATUS_ACCESS_DENIED Pavel Shilovsky
  1 sibling, 1 reply; 5+ messages in thread
From: Pavel Shilovsky @ 2011-08-25 21:04 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Reorganize code and make it send qpath info request only for a full
path (//server/share/prefixpath) rather than request for every path
compoment. In this case we end up with negative dentries for all
components except full one and we will instantiate them later if
such a mount is requested.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsfs.c  |  123 +++++++++++++++++++++++++++++++----------------------
 fs/cifs/cifsfs.h  |    3 +-
 fs/cifs/inode.c   |    7 ++-
 fs/cifs/readdir.c |    9 +++-
 4 files changed, 85 insertions(+), 57 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 0435bb9..33a2e1e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -95,14 +95,13 @@ mempool_t *smb2_mid_poolp;
 static struct kmem_cache *smb2_mid_cachep;
 #endif /* CONFIG_CIFS_SMB2 */
 
-static int
+static void
 cifs_read_super(struct super_block *sb)
 {
-	struct inode *inode;
-	struct cifs_sb_info *cifs_sb;
-	int rc = 0;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-	cifs_sb = CIFS_SB(sb);
+	/* BB should we make this contingent on mount parm? */
+	sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
 		sb->s_flags |= MS_POSIXACL;
@@ -120,26 +119,6 @@ cifs_read_super(struct super_block *sb)
 	sb->s_bdi = &cifs_sb->bdi;
 	sb->s_blocksize = CIFS_MAX_MSGSIZE;
 	sb->s_blocksize_bits = 14;	/* default 2**14 = CIFS_MAX_MSGSIZE */
-	inode = cifs_root_iget(sb);
-
-	if (IS_ERR(inode)) {
-		rc = PTR_ERR(inode);
-		inode = NULL;
-		goto out_no_root;
-	}
-
-	sb->s_root = d_alloc_root(inode);
-
-	if (!sb->s_root) {
-		rc = -ENOMEM;
-		goto out_no_root;
-	}
-
-	/* do that *after* d_alloc_root() - we want NULL ->d_op for root here */
-	if (cifs_sb_master_tcon(cifs_sb)->nocase)
-		sb->s_d_op = &cifs_ci_dentry_ops;
-	else
-		sb->s_d_op = &cifs_dentry_ops;
 
 #ifdef CIFS_NFSD_EXPORT
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
@@ -148,14 +127,7 @@ cifs_read_super(struct super_block *sb)
 	}
 #endif /* CIFS_NFSD_EXPORT */
 
-	return 0;
-
-out_no_root:
-	cERROR(1, "cifs_read_super: get root inode failed");
-	if (inode)
-		iput(inode);
-
-	return rc;
+	sb->s_flags |= MS_ACTIVE;
 }
 
 static void cifs_kill_sb(struct super_block *sb)
@@ -529,6 +501,17 @@ static const struct super_operations cifs_super_ops = {
 #endif
 };
 
+static struct dentry *
+cifs_alloc_root(struct super_block *sb)
+{
+	struct qstr q;
+
+	q.name = "/";
+	q.len = 1;
+	q.hash = full_name_hash(q.name, q.len);
+	return d_alloc_pseudo(sb, &q);
+}
+
 /*
  * Get root dentry from superblock according to prefix path mount option.
  * Return dentry with refcount + 1 on success and NULL otherwise.
@@ -536,8 +519,10 @@ static const struct super_operations cifs_super_ops = {
 static struct dentry *
 cifs_get_root(struct smb_vol *vol, struct super_block *sb)
 {
-	struct dentry *dentry;
+	struct dentry *dentry, *found;
+	struct inode *inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	struct qstr q;
 	char *full_path = NULL;
 	char *s, *p;
 	char sep;
@@ -550,13 +535,29 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
 
 	cFYI(1, "Get root dentry for %s", full_path);
 
+	if (!sb->s_root) {
+		sb->s_root = cifs_alloc_root(sb);
+		if (IS_ERR(sb->s_root)) {
+			dentry = ERR_PTR(-ENOMEM);
+			goto out;
+		}
+
+		/*
+		 * do that *after* cifs_alloc_root() - we want NULL ->d_op for
+		 * root here
+		 */
+		if (cifs_sb_master_tcon(cifs_sb)->nocase)
+			sb->s_d_op = &cifs_ci_dentry_ops;
+		else
+			sb->s_d_op = &cifs_dentry_ops;
+	}
+
 	xid = GetXid();
 	sep = CIFS_DIR_SEP(cifs_sb);
 	dentry = dget(sb->s_root);
 	p = s = full_path;
 
 	do {
-		struct inode *dir = dentry->d_inode;
 		struct dentry *child;
 
 		/* skip separators */
@@ -569,16 +570,45 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
 		while (*s && *s != sep)
 			s++;
 
-		mutex_lock(&dir->i_mutex);
-		child = lookup_one_len(p, dentry, s - p);
-		mutex_unlock(&dir->i_mutex);
+		q.name = p;
+		q.len = s - p;
+		if (dentry->d_flags & DCACHE_OP_HASH)
+			dentry->d_op->d_hash(dentry, dentry->d_inode, &q);
+		else
+			q.hash = full_name_hash(q.name, q.len);
+
+		child = d_lookup(dentry, &q);
+		if (!child) {
+			child = d_alloc(dentry, &q);
+			if (IS_ERR(child)) {
+				dput(dentry);
+				dentry = ERR_CAST(child);
+				break;
+			}
+			d_rehash(child);
+		}
 		dput(dentry);
 		dentry = child;
-		if (!dentry->d_inode) {
+	} while (!IS_ERR(dentry));
+
+	if (IS_ERR(dentry))
+		goto out;
+
+	if (!dentry->d_inode) {
+		inode = cifs_mntroot_iget(sb, full_path);
+		if (IS_ERR(inode)) {
 			dput(dentry);
-			dentry = ERR_PTR(-ENOENT);
+			dentry = ERR_CAST(inode);
+			goto out;
 		}
-	} while (!IS_ERR(dentry));
+
+		found = d_instantiate_unique(dentry, inode);
+		if (found) {
+			dput(dentry);
+			dentry = dget(found);
+		}
+	}
+out:
 	_FreeXid(xid);
 	kfree(full_path);
 	return dentry;
@@ -646,16 +676,7 @@ cifs_do_mount(struct file_system_type *fs_type,
 		cifs_umount(cifs_sb);
 	} else {
 		sb->s_flags = flags;
-		/* BB should we make this contingent on mount parm? */
-		sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
-
-		rc = cifs_read_super(sb);
-		if (rc) {
-			root = ERR_PTR(rc);
-			goto out_super;
-		}
-
-		sb->s_flags |= MS_ACTIVE;
+		cifs_read_super(sb);
 	}
 
 	root = cifs_get_root(volume_info, sb);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 3145c18..47d9ec9 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -43,7 +43,8 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf;
 
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
-extern struct inode *cifs_root_iget(struct super_block *);
+extern struct inode *cifs_mntroot_iget(struct super_block *sb,
+				       const char *full_path);
 extern int cifs_create(struct inode *, struct dentry *, int,
 		       struct nameidata *);
 extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index aee0c0b..dedfed3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -931,7 +931,7 @@ retry_iget5_locked:
 }
 
 /* gets root inode */
-struct inode *cifs_root_iget(struct super_block *sb)
+struct inode *cifs_mntroot_iget(struct super_block *sb, const char *full_path)
 {
 	int xid;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -941,9 +941,10 @@ struct inode *cifs_root_iget(struct super_block *sb)
 
 	xid = GetXid();
 	if (tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
+		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
 	else
-		rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
+		rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid,
+					 NULL);
 
 	if (!inode) {
 		inode = ERR_PTR(rc);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 75e8b5c..7475cba 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -708,6 +708,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	char *tmp_buf = NULL;
 	char *end_of_smb;
 	unsigned int max_len;
+	ino_t ino;
 
 	xid = GetXid();
 
@@ -732,8 +733,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 		}
 		file->f_pos++;
 	case 1:
-		if (filldir(direntry, "..", 2, file->f_pos,
-		     parent_ino(file->f_path.dentry), DT_DIR) < 0) {
+		if (!file->f_path.dentry->d_parent->d_inode) {
+			cFYI(1, "parent dir is negative, filling as current");
+			ino = file->f_path.dentry->d_inode->i_ino;
+		} else
+			ino = parent_ino(file->f_path.dentry);
+		if (filldir(direntry, "..", 2, file->f_pos, ino, DT_DIR) < 0) {
 			cERROR(1, "Filldir for parent dir failed");
 			rc = -ENOMEM;
 			break;
-- 
1.7.1

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

* Re: mount.cifs with "prefixpath" option getting NT_STATUS_ACCESS_DENIED
       [not found] ` <CAD4ZOMwcYFut0o8Krw-Z+tiGwz9VNvy4jRvwMcXv42P60pJxbg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2011-08-25 21:04   ` [PATCH] CIFS: Fix NT_STATUS_ACCESS for moutn with prefixpath option Pavel Shilovsky
@ 2011-08-25 21:08   ` Pavel Shilovsky
       [not found]     ` <CAKywueRh-c3JoqdGSg4iTSX+KvCbwVpS4GUwprFOkpQwaF4=3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 5+ messages in thread
From: Pavel Shilovsky @ 2011-08-25 21:08 UTC (permalink / raw)
  To: Rafael Ganascim, Jeff Layton, Al Viro; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2011/8/22 Rafael Ganascim <rganascim-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> Hi,
>
> I think that this problem is related to:
>
> http://article.gmane.org/gmane.linux.kernel.cifs/3878
>
>
> I have this fileserver structure:
>  - complete path: //fileserver-la-01/ti$/geral/
>  - //fileserver-la-01/ti$: in this parent dir, my user don't have
> permission to access
>
>
> Using the kernel version 2.6.38 the mount reports:
>
> # mount -v /mnt/xxxx/latigeral/
> parsing options: rw,credentials=/etc/credentials,uid=1000
>
> mount.cifs kernel mount options
> unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/
> #
>
>
> Using the kernel 3.0.2:
>
> # mount -v /mnt/xxxx/latigeral
> parsing options: rw,credentials=/etc/credentials,uid=1000
>
> mount.cifs kernel mount options
> unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/
> mount error(13): Permission denied
> Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)
> #
>
> The cifsFYI messages are in the attachments, cifsFYI.txt.
>
> To workaround this problem (in my box), I had set the 'full_path'
> (from prefixpath) in the call to cifs_get_inode_info in the function
> cifs_root_iget (~ inode.c:888), if the prefixpath isn't null. This
> worked for me, but it's bad solution, I think (i'm not a programmer :(
> ).
>
> What do you think about this problem? There are a 'good' solution for it?
>
>
> Thanks,
> --
>
> Rafael Ganascim
>

Hi!

I posted the patch "CIFS: Fix NT_STATUS_ACCESS for moutn with
prefixpath option" to the list - that should help.

Jeff, Al, can you comment on this, please?

-- 
Best regards,
Pavel Shilovsky.

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

* Re: mount.cifs with "prefixpath" option getting NT_STATUS_ACCESS_DENIED
       [not found]     ` <CAKywueRh-c3JoqdGSg4iTSX+KvCbwVpS4GUwprFOkpQwaF4=3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-08-26  6:53       ` Pavel Shilovsky
  0 siblings, 0 replies; 5+ messages in thread
From: Pavel Shilovsky @ 2011-08-26  6:53 UTC (permalink / raw)
  To: Rafael Ganascim, Jeff Layton, Al Viro; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2011/8/26 Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> 2011/8/22 Rafael Ganascim <rganascim-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> Hi,
>>
>> I think that this problem is related to:
>>
>> http://article.gmane.org/gmane.linux.kernel.cifs/3878
>>
>>
>> I have this fileserver structure:
>>  - complete path: //fileserver-la-01/ti$/geral/
>>  - //fileserver-la-01/ti$: in this parent dir, my user don't have
>> permission to access
>>
>>
>> Using the kernel version 2.6.38 the mount reports:
>>
>> # mount -v /mnt/xxxx/latigeral/
>> parsing options: rw,credentials=/etc/credentials,uid=1000
>>
>> mount.cifs kernel mount options
>> unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/
>> #
>>
>>
>> Using the kernel 3.0.2:
>>
>> # mount -v /mnt/xxxx/latigeral
>> parsing options: rw,credentials=/etc/credentials,uid=1000
>>
>> mount.cifs kernel mount options
>> unc=//fileserver-la-01\ti$,user=xxxxxx,pass=xxxxx,ver=1,rw,credentials=/etc/credentials,uid=1000,prefixpath=geral/
>> mount error(13): Permission denied
>> Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)
>> #
>>
>> The cifsFYI messages are in the attachments, cifsFYI.txt.
>>
>> To workaround this problem (in my box), I had set the 'full_path'
>> (from prefixpath) in the call to cifs_get_inode_info in the function
>> cifs_root_iget (~ inode.c:888), if the prefixpath isn't null. This
>> worked for me, but it's bad solution, I think (i'm not a programmer :(
>> ).
>>
>> What do you think about this problem? There are a 'good' solution for it?
>>
>>
>> Thanks,
>> --
>>
>> Rafael Ganascim
>>
>
> Hi!
>
> I posted the patch "CIFS: Fix NT_STATUS_ACCESS for moutn with
> prefixpath option" to the list - that should help.
>
> Jeff, Al, can you comment on this, please?
>
> --
> Best regards,
> Pavel Shilovsky.
>

Sorry - wrong title. resend as "CIFS: Fix NT_STATUS_ACCESS_DENIED for
mounts with prefixpath option" patch.

-- 
Best regards,
Pavel Shilovsky.

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

* Re: [PATCH] CIFS: Fix NT_STATUS_ACCESS for moutn with prefixpath option
  2011-08-25 21:04   ` [PATCH] CIFS: Fix NT_STATUS_ACCESS for moutn with prefixpath option Pavel Shilovsky
@ 2014-04-23 19:27     ` Ryan Johnson
  0 siblings, 0 replies; 5+ messages in thread
From: Ryan Johnson @ 2014-04-23 19:27 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Pavel Shilovsky <piastry@...> writes:

> 
> Reorganize code and make it send qpath info request only for a full
> path (//server/share/prefixpath) rather than request for every path
> compoment. In this case we end up with negative dentries for all
> components except full one and we will instantiate them later if
> such a mount is requested.
> 
> Signed-off-by: Pavel Shilovsky <piastry@...>
> ---
>  fs/cifs/cifsfs.c  |  123
+++++++++++++++++++++++++++++++----------------------
>  fs/cifs/cifsfs.h  |    3 +-
>  fs/cifs/inode.c   |    7 ++-
>  fs/cifs/readdir.c |    9 +++-
>  4 files changed, 85 insertions(+), 57 deletions(-)
> 
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index 0435bb9..33a2e1e 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
>  <at>  <at>  -95,14 +95,13  <at>  <at>  mempool_t *smb2_mid_poolp;
>  static struct kmem_cache *smb2_mid_cachep;
>  #endif /* CONFIG_CIFS_SMB2 */
> 
> -static int
> +static void
>  cifs_read_super(struct super_block *sb)
>  {
> -	struct inode *inode;
> -	struct cifs_sb_info *cifs_sb;
> -	int rc = 0;
> +	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
> 
> -	cifs_sb = CIFS_SB(sb);
> +	/* BB should we make this contingent on mount parm? */
> +	sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
> 
>  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
>  		sb->s_flags |= MS_POSIXACL;
>  <at>  <at>  -120,26 +119,6  <at>  <at>  cifs_read_super(struct
super_block *sb)
>  	sb->s_bdi = &cifs_sb->bdi;
>  	sb->s_blocksize = CIFS_MAX_MSGSIZE;
>  	sb->s_blocksize_bits = 14;	/* default 2**14 = CIFS_MAX_MSGSIZE */
> -	inode = cifs_root_iget(sb);
> -
> -	if (IS_ERR(inode)) {
> -		rc = PTR_ERR(inode);
> -		inode = NULL;
> -		goto out_no_root;
> -	}
> -
> -	sb->s_root = d_alloc_root(inode);
> -
> -	if (!sb->s_root) {
> -		rc = -ENOMEM;
> -		goto out_no_root;
> -	}
> -
> -	/* do that *after* d_alloc_root() - we want NULL ->d_op for root here */
> -	if (cifs_sb_master_tcon(cifs_sb)->nocase)
> -		sb->s_d_op = &cifs_ci_dentry_ops;
> -	else
> -		sb->s_d_op = &cifs_dentry_ops;
> 
>  #ifdef CIFS_NFSD_EXPORT
>  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
>  <at>  <at>  -148,14 +127,7  <at>  <at>  cifs_read_super(struct
super_block *sb)
>  	}
>  #endif /* CIFS_NFSD_EXPORT */
> 
> -	return 0;
> -
> -out_no_root:
> -	cERROR(1, "cifs_read_super: get root inode failed");
> -	if (inode)
> -		iput(inode);
> -
> -	return rc;
> +	sb->s_flags |= MS_ACTIVE;
>  }
> 
>  static void cifs_kill_sb(struct super_block *sb)
>  <at>  <at>  -529,6 +501,17  <at>  <at>  static const struct
super_operations cifs_super_ops = {
>  #endif
>  };
> 
> +static struct dentry *
> +cifs_alloc_root(struct super_block *sb)
> +{
> +	struct qstr q;
> +
> +	q.name = "/";
> +	q.len = 1;
> +	q.hash = full_name_hash(q.name, q.len);
> +	return d_alloc_pseudo(sb, &q);
> +}
> +
>  /*
>   * Get root dentry from superblock according to prefix path mount option.
>   * Return dentry with refcount + 1 on success and NULL otherwise.
>  <at>  <at>  -536,8 +519,10  <at>  <at>  static const struct
super_operations cifs_super_ops = {
>  static struct dentry *
>  cifs_get_root(struct smb_vol *vol, struct super_block *sb)
>  {
> -	struct dentry *dentry;
> +	struct dentry *dentry, *found;
> +	struct inode *inode;
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
> +	struct qstr q;
>  	char *full_path = NULL;
>  	char *s, *p;
>  	char sep;
>  <at>  <at>  -550,13 +535,29  <at>  <at>  cifs_get_root(struct smb_vol
*vol, struct super_block *sb)
> 
>  	cFYI(1, "Get root dentry for %s", full_path);
> 
> +	if (!sb->s_root) {
> +		sb->s_root = cifs_alloc_root(sb);
> +		if (IS_ERR(sb->s_root)) {
> +			dentry = ERR_PTR(-ENOMEM);
> +			goto out;
> +		}
> +
> +		/*
> +		 * do that *after* cifs_alloc_root() - we want NULL ->d_op for
> +		 * root here
> +		 */
> +		if (cifs_sb_master_tcon(cifs_sb)->nocase)
> +			sb->s_d_op = &cifs_ci_dentry_ops;
> +		else
> +			sb->s_d_op = &cifs_dentry_ops;
> +	}
> +
>  	xid = GetXid();
>  	sep = CIFS_DIR_SEP(cifs_sb);
>  	dentry = dget(sb->s_root);
>  	p = s = full_path;
> 
>  	do {
> -		struct inode *dir = dentry->d_inode;
>  		struct dentry *child;
> 
>  		/* skip separators */
>  <at>  <at>  -569,16 +570,45  <at>  <at>  cifs_get_root(struct smb_vol
*vol, struct super_block *sb)
>  		while (*s && *s != sep)
>  			s++;
> 
> -		mutex_lock(&dir->i_mutex);
> -		child = lookup_one_len(p, dentry, s - p);
> -		mutex_unlock(&dir->i_mutex);
> +		q.name = p;
> +		q.len = s - p;
> +		if (dentry->d_flags & DCACHE_OP_HASH)
> +			dentry->d_op->d_hash(dentry, dentry->d_inode, &q);
> +		else
> +			q.hash = full_name_hash(q.name, q.len);
> +
> +		child = d_lookup(dentry, &q);
> +		if (!child) {
> +			child = d_alloc(dentry, &q);
> +			if (IS_ERR(child)) {
> +				dput(dentry);
> +				dentry = ERR_CAST(child);
> +				break;
> +			}
> +			d_rehash(child);
> +		}
>  		dput(dentry);
>  		dentry = child;
> -		if (!dentry->d_inode) {
> +	} while (!IS_ERR(dentry));
> +
> +	if (IS_ERR(dentry))
> +		goto out;
> +
> +	if (!dentry->d_inode) {
> +		inode = cifs_mntroot_iget(sb, full_path);
> +		if (IS_ERR(inode)) {
>  			dput(dentry);
> -			dentry = ERR_PTR(-ENOENT);
> +			dentry = ERR_CAST(inode);
> +			goto out;
>  		}
> -	} while (!IS_ERR(dentry));
> +
> +		found = d_instantiate_unique(dentry, inode);
> +		if (found) {
> +			dput(dentry);
> +			dentry = dget(found);
> +		}
> +	}
> +out:
>  	_FreeXid(xid);
>  	kfree(full_path);
>  	return dentry;
>  <at>  <at>  -646,16 +676,7  <at>  <at>  cifs_do_mount(struct
file_system_type *fs_type,
>  		cifs_umount(cifs_sb);
>  	} else {
>  		sb->s_flags = flags;
> -		/* BB should we make this contingent on mount parm? */
> -		sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
> -
> -		rc = cifs_read_super(sb);
> -		if (rc) {
> -			root = ERR_PTR(rc);
> -			goto out_super;
> -		}
> -
> -		sb->s_flags |= MS_ACTIVE;
> +		cifs_read_super(sb);
>  	}
> 
>  	root = cifs_get_root(volume_info, sb);
> diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
> index 3145c18..47d9ec9 100644
> --- a/fs/cifs/cifsfs.h
> +++ b/fs/cifs/cifsfs.h
>  <at>  <at>  -43,7 +43,8  <at>  <at>  extern const struct
address_space_operations cifs_addr_ops_smallbuf;
> 
>  /* Functions related to inodes */
>  extern const struct inode_operations cifs_dir_inode_ops;
> -extern struct inode *cifs_root_iget(struct super_block *);
> +extern struct inode *cifs_mntroot_iget(struct super_block *sb,
> +				       const char *full_path);
>  extern int cifs_create(struct inode *, struct dentry *, int,
>  		       struct nameidata *);
>  extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index aee0c0b..dedfed3 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
>  <at>  <at>  -931,7 +931,7  <at>  <at>  retry_iget5_locked:
>  }
> 
>  /* gets root inode */
> -struct inode *cifs_root_iget(struct super_block *sb)
> +struct inode *cifs_mntroot_iget(struct super_block *sb, const char
*full_path)
>  {
>  	int xid;
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
>  <at>  <at>  -941,9 +941,10  <at>  <at>  struct inode
*cifs_root_iget(struct super_block *sb)
> 
>  	xid = GetXid();
>  	if (tcon->unix_ext)
> -		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
> +		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
>  	else
> -		rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
> +		rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid,
> +					 NULL);
> 
>  	if (!inode) {
>  		inode = ERR_PTR(rc);
> diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
> index 75e8b5c..7475cba 100644
> --- a/fs/cifs/readdir.c
> +++ b/fs/cifs/readdir.c
>  <at>  <at>  -708,6 +708,7  <at>  <at>  int cifs_readdir(struct file
*file, void *direntry, filldir_t filldir)
>  	char *tmp_buf = NULL;
>  	char *end_of_smb;
>  	unsigned int max_len;
> +	ino_t ino;
> 
>  	xid = GetXid();
> 
>  <at>  <at>  -732,8 +733,12  <at>  <at>  int cifs_readdir(struct file
*file, void *direntry, filldir_t filldir)
>  		}
>  		file->f_pos++;
>  	case 1:
> -		if (filldir(direntry, "..", 2, file->f_pos,
> -		     parent_ino(file->f_path.dentry), DT_DIR) < 0) {
> +		if (!file->f_path.dentry->d_parent->d_inode) {
> +			cFYI(1, "parent dir is negative, filling as current");
> +			ino = file->f_path.dentry->d_inode->i_ino;
> +		} else
> +			ino = parent_ino(file->f_path.dentry);
> +		if (filldir(direntry, "..", 2, file->f_pos, ino, DT_DIR) < 0) {
>  			cERROR(1, "Filldir for parent dir failed");
>  			rc = -ENOMEM;
>  			break;


Hi Pavel & CIFS developers,

Thank you for this patch. Presently, this is the the only way I can access
certain shares (on a windows server) at my organization. It is a
security-concerned organization so permissions are denied for any directory
where they are not explicitly needed, which leads to this issue.

Most of the Linux and Mac users at my organization now use Windows VMs or
older kernel/OS versions to access these shares. I have been using your
patch and modifying it to work with each Linux (Ubuntu) kernel version.

I thought I might as well post my latest modification of your patch, which
has worked for me for kernels 3.11 and 3.13. Is there any chance that this
issue will be addressed in an official version of CIFS in the future?

Here is the patch:

<BEGIN PATCH>
diff -uNr a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
--- a/fs/cifs/cifsfs.c	2014-01-19 11:10:51.000000000 -0500
+++ b/fs/cifs/cifsfs.c	2014-01-14 14:33:30.137967187 -0500
@@ -115,15 +115,14 @@
 		deactivate_super(sb);
 }
 
-static int
+static void
 cifs_read_super(struct super_block *sb)
 {
-	struct inode *inode;
-	struct cifs_sb_info *cifs_sb;
 	struct cifs_tcon *tcon;
-	int rc = 0;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-	cifs_sb = CIFS_SB(sb);
+	/* BB should we make this contingent on mount parm? */
+	sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
 	tcon = cifs_sb_master_tcon(cifs_sb);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
@@ -142,23 +141,6 @@
 	sb->s_bdi = &cifs_sb->bdi;
 	sb->s_blocksize = CIFS_MAX_MSGSIZE;
 	sb->s_blocksize_bits = 14;	/* default 2**14 = CIFS_MAX_MSGSIZE */
-	inode = cifs_root_iget(sb);
-
-	if (IS_ERR(inode)) {
-		rc = PTR_ERR(inode);
-		goto out_no_root;
-	}
-
-	if (tcon->nocase)
-		sb->s_d_op = &cifs_ci_dentry_ops;
-	else
-		sb->s_d_op = &cifs_dentry_ops;
-
-	sb->s_root = d_make_root(inode);
-	if (!sb->s_root) {
-		rc = -ENOMEM;
-		goto out_no_root;
-	}
 
 #ifdef CONFIG_CIFS_NFSD_EXPORT
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
@@ -167,11 +149,7 @@
 	}
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-	return 0;
-
-out_no_root:
-	cifs_dbg(VFS, "%s: get root inode failed\n", __func__);
-	return rc;
+	sb->s_flags |= MS_ACTIVE;
 }
 
 static void cifs_kill_sb(struct super_block *sb)
@@ -556,6 +534,17 @@
 #endif
 };
 
+static struct dentry *
+cifs_alloc_root(struct super_block *sb)
+{
+	struct qstr q;
+
+	q.name = "/";
+	q.len = 1;
+	q.hash = full_name_hash(q.name, q.len);
+	return d_alloc_pseudo(sb, &q);
+}
+
 /*
  * Get root dentry from superblock according to prefix path mount option.
  * Return dentry with refcount + 1 on success and NULL otherwise.
@@ -563,8 +552,10 @@
 static struct dentry *
 cifs_get_root(struct smb_vol *vol, struct super_block *sb)
 {
-	struct dentry *dentry;
+	struct dentry *dentry, *found;
+	struct inode *inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	struct qstr q;
 	char *full_path = NULL;
 	char *s, *p;
 	char sep;
@@ -576,25 +567,30 @@
 
 	cifs_dbg(FYI, "Get root dentry for %s\n", full_path);
 
+	if (!sb->s_root) {
+		sb->s_root = cifs_alloc_root(sb);
+		if (IS_ERR(sb->s_root)) {
+			dentry = ERR_PTR(-ENOMEM);
+			goto out;
+		}
+
+		/*
+		 * do that *after* cifs_alloc_root() - we want NULL ->d_op for
+		 * root here
+		 */
+		if (cifs_sb_master_tcon(cifs_sb)->nocase)
+			sb->s_d_op = &cifs_ci_dentry_ops;
+		else
+			sb->s_d_op = &cifs_dentry_ops;
+	}
+
 	sep = CIFS_DIR_SEP(cifs_sb);
 	dentry = dget(sb->s_root);
 	p = s = full_path;
 
 	do {
-		struct inode *dir = dentry->d_inode;
 		struct dentry *child;
 
-		if (!dir) {
-			dput(dentry);
-			dentry = ERR_PTR(-ENOENT);
-			break;
-		}
-		if (!S_ISDIR(dir->i_mode)) {
-			dput(dentry);
-			dentry = ERR_PTR(-ENOTDIR);
-			break;
-		}
-
 		/* skip separators */
 		while (*s == sep)
 			s++;
@@ -605,12 +601,44 @@
 		while (*s && *s != sep)
 			s++;
 
-		mutex_lock(&dir->i_mutex);
-		child = lookup_one_len(p, dentry, s - p);
-		mutex_unlock(&dir->i_mutex);
+		q.name = p;
+		q.len = s - p;
+		if (dentry->d_flags & DCACHE_OP_HASH)
+			dentry->d_op->d_hash(dentry, &q);
+		else
+			q.hash = full_name_hash(q.name, q.len);
+
+		child = d_lookup(dentry, &q);
+		if (!child) {
+			child = d_alloc(dentry, &q);
+			if (IS_ERR(child)) {
+				dput(dentry);
+				dentry = ERR_CAST(child);
+				break;
+			}
+			d_rehash(child);
+		}
 		dput(dentry);
 		dentry = child;
 	} while (!IS_ERR(dentry));
+
+	if (IS_ERR(dentry))
+		goto out;
+
+	if (!dentry->d_inode) {
+		inode = cifs_mntroot_iget(sb, full_path);
+		if (IS_ERR(inode)) {
+			dput(dentry);
+			dentry = ERR_CAST(inode);
+			goto out;
+ 		}
+		found = d_instantiate_unique(dentry, inode);
+		if (found) {
+			dput(dentry);
+			dentry = dget(found);
+		}
+	}
+out:
 	kfree(full_path);
 	return dentry;
 }
@@ -680,13 +708,8 @@
 		cifs_dbg(FYI, "Use existing superblock\n");
 		cifs_umount(cifs_sb);
 	} else {
-		rc = cifs_read_super(sb);
-		if (rc) {
-			root = ERR_PTR(rc);
-			goto out_super;
-		}
-
-		sb->s_flags |= MS_ACTIVE;
+		sb->s_flags = flags;
+		cifs_read_super(sb);
 	}
 
 	root = cifs_get_root(volume_info, sb);
diff -uNr a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
--- a/fs/cifs/cifsfs.h	2013-09-02 16:46:10.000000000 -0400
+++ b/fs/cifs/cifsfs.h	2014-01-14 13:22:23.865874718 -0500
@@ -47,7 +47,7 @@
 
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
-extern struct inode *cifs_root_iget(struct super_block *);
+extern struct inode *cifs_mntroot_iget(struct super_block *sb, const char
*full_path);
 extern int cifs_create(struct inode *, struct dentry *, umode_t,
 		       bool excl);
 extern int cifs_atomic_open(struct inode *, struct dentry *,
diff -uNr a/fs/cifs/inode.c b/fs/cifs/inode.c
--- a/fs/cifs/inode.c	2013-09-02 16:46:10.000000000 -0400
+++ b/fs/cifs/inode.c	2014-01-14 13:22:23.865874718 -0500
@@ -883,7 +883,7 @@
 }
 
 /* gets root inode */
-struct inode *cifs_root_iget(struct super_block *sb)
+struct inode *cifs_mntroot_iget(struct super_block *sb, const char *full_path)
 {
 	unsigned int xid;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -893,9 +893,10 @@
 
 	xid = get_xid();
 	if (tcon->unix_ext)
-		rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
+		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
 	else
-		rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
+		rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid,
+					 NULL);
 
 	if (!inode) {
 		inode = ERR_PTR(rc);
diff -uNr a/fs/cifs/readdir.c b/fs/cifs/readdir.c
--- a/fs/cifs/readdir.c	2013-09-02 16:46:10.000000000 -0400
+++ b/fs/cifs/readdir.c	2014-01-18 21:01:00.644310932 -0500
@@ -794,6 +794,7 @@
 	char *tmp_buf = NULL;
 	char *end_of_smb;
 	unsigned int max_len;
+	ino_t ino;
 
 	xid = get_xid();
 
@@ -808,8 +809,30 @@
 			goto rddir2_exit;
 	}
 
-	if (!dir_emit_dots(file, ctx))
-		goto rddir2_exit;
+	//	if (!dir_emit_dots(file, ctx))
+	//	goto rddir2_exit;
+
+	//Need to edit the process in dir_emit_dots in include/linux/fs.h
+	//That function is copied here and edited. The original call to 
+	//dir_emit_dots is removed.
+
+	if (ctx->pos == 0) {
+		if (!dir_emit_dot(file, ctx))
+			goto rddir2_exit;
+		ctx->pos = 1;
+	}
+	if (ctx->pos == 1) {
+		if (!file->f_path.dentry->d_parent->d_inode) {
+			ino = file->f_path.dentry->d_inode->i_ino;
+			if(!(ctx->actor(ctx, "..", 2, ctx->pos, ino, DT_DIR) == 0))
+				goto rddir2_exit;
+		}
+		else {
+			if (!dir_emit_dotdot(file, ctx))
+				goto rddir2_exit;
+		}
+		ctx->pos = 2;
+	}
 
 	/* 1) If search is active,
 		is in current search buffer?
<END PATCH>

Thanks,

-Ryan

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

end of thread, other threads:[~2014-04-23 19:27 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-22 17:30 mount.cifs with "prefixpath" option getting NT_STATUS_ACCESS_DENIED Rafael Ganascim
     [not found] ` <CAD4ZOMwcYFut0o8Krw-Z+tiGwz9VNvy4jRvwMcXv42P60pJxbg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-08-25 21:04   ` [PATCH] CIFS: Fix NT_STATUS_ACCESS for moutn with prefixpath option Pavel Shilovsky
2014-04-23 19:27     ` Ryan Johnson
2011-08-25 21:08   ` mount.cifs with "prefixpath" option getting NT_STATUS_ACCESS_DENIED Pavel Shilovsky
     [not found]     ` <CAKywueRh-c3JoqdGSg4iTSX+KvCbwVpS4GUwprFOkpQwaF4=3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-08-26  6:53       ` Pavel Shilovsky

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.