Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e4bbde9 authored by Steve French's avatar Steve French
Browse files

[CIFS] Enable DFS support for Unix query path info



Final piece for handling DFS in unix_query_path_info, constructing a
fake inode for the junction directory which the submount will cover.

Acked-by: default avatarIgor Mammedov <niallain@gmail.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 89562b77
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
Igor Mammedov (DFS support)

Test case and Bug Report contributors
-------------------------------------
+2 −0
Original line number Diff line number Diff line
Version 1.53
------------
DFS support added (Microsoft Distributed File System client support needed
for referrals which enable a hierarchical name space among servers).

Version 1.52
------------
+8 −7
Original line number Diff line number Diff line
Version 1.52 January 3, 2008
Version 1.53 May 20, 2008

A Partial List of Missing Features
==================================
@@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in
fs/cifs/connect.c and add back in NTLMSSP code if any servers
need it

e) ms-dfs and ms-dfs host name resolution cleanup

f) fix NTLMv2 signing when two mounts with different users to same
e) fix NTLMv2 signing when two mounts with different users to same
server.

g) Directory entry caching relies on a 1 second timer, rather than 
f) Directory entry caching relies on a 1 second timer, rather than 
using FindNotify or equivalent.  - (started)

h) quota support (needs minor kernel change since quota calls
g) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems)

i) investigate sync behavior (including syncpage) and check  
h) investigate sync behavior (including syncpage) and check  
for proper behavior of intr/nointr

i) improve support for very old servers (OS/2 and Win9x for example)
Including support for changing the time remotely (utimes command).

j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases.

+74 −43
Original line number Diff line number Diff line
@@ -161,36 +161,69 @@ static void cifs_unix_info_to_inode(struct inode *inode,
	spin_unlock(&inode->i_lock);
}

static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
			       struct super_block *sb)
{
	struct inode *pinode = NULL;

	memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0);

/*	__le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
	__le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
	__u64 UniqueId = 0;  */
	pfnd_dat->LastStatusChange =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->LastAccessTime =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->LastModificationTime =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
	pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
	pfnd_dat->Nlinks = cpu_to_le64(2);
	if (sb->s_root)
		pinode = sb->s_root->d_inode;
	if (pinode == NULL)
		return;

	/* fill in default values for the remaining based on root
	   inode since we can not query the server for this inode info */
	pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
	pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
	pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
	pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
}

int cifs_get_inode_info_unix(struct inode **pinode,
	const unsigned char *full_path, struct super_block *sb, int xid)
{
	int rc = 0;
	FILE_UNIX_BASIC_INFO findData;
	FILE_UNIX_BASIC_INFO find_data;
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	bool is_dfs_referral = false;
	struct cifsInodeInfo *cifsInfo;
	__u64 num_of_bytes;
	__u64 end_of_file;

	pTcon = cifs_sb->tcon;
	cFYI(1, ("Getting info on %s", full_path));

try_again_CIFSSMBUnixQPathInfo:
	/* could have done a find first instead but this returns more info */
	rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
	rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
				  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
					CIFS_MOUNT_MAP_SPECIAL_CHR);
/*	dump_mem("\nUnixQPathInfo return data", &findData,
		 sizeof(findData)); */
	if (rc) {
		if (rc == -EREMOTE && !is_dfs_referral) {
			is_dfs_referral = true;
			goto try_again_CIFSSMBUnixQPathInfo;
			cERROR(1, ("DFS ref")); /* BB removeme BB */
			/* for DFS, server does not give us real inode data */
			fill_fake_finddataunix(&find_data, sb);
			rc = 0;
		}
		goto cgiiu_exit;
	} else {
		struct cifsInodeInfo *cifsInfo;
		__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
		__u64 end_of_file = le64_to_cpu(findData.EndOfFile);
	}
	num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
	end_of_file = le64_to_cpu(find_data.EndOfFile);

	/* get new inode */
	if (*pinode == NULL) {
@@ -200,12 +233,12 @@ int cifs_get_inode_info_unix(struct inode **pinode,
		goto cgiiu_exit;
		}
		/* Is an i_ino of zero legal? */
		/* note ino incremented to unique num in new_inode */
		/* Are there sanity checks we can use to ensure that
		   the server is really filling in that field? */
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
				(*pinode)->i_ino =
					(unsigned long)findData.UniqueId;
			} /* note ino incremented to unique num in new_inode */
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
			(*pinode)->i_ino = (unsigned long)find_data.UniqueId;

		if (sb->s_flags & MS_NOATIME)
			(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;

@@ -221,8 +254,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
	/* this is ok to set on every inode revalidate */
	atomic_set(&cifsInfo->inUse, 1);

		cifs_unix_info_to_inode(inode, &findData, 0);

	cifs_unix_info_to_inode(inode, &find_data, 0);

	if (num_of_bytes < end_of_file)
		cFYI(1, ("allocation size less than end of file"));
@@ -231,7 +263,6 @@ int cifs_get_inode_info_unix(struct inode **pinode,
		(unsigned long long)inode->i_blocks));

	cifs_set_ops(inode, is_dfs_referral);
	}
cgiiu_exit:
	return rc;
}