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

[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
...@@ -36,6 +36,7 @@ Miklos Szeredi ...@@ -36,6 +36,7 @@ Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version. Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support) Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
Igor Mammedov (DFS support)
Test case and Bug Report contributors Test case and Bug Report contributors
------------------------------------- -------------------------------------
......
Version 1.53 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 Version 1.52
------------ ------------
......
Version 1.52 January 3, 2008 Version 1.53 May 20, 2008
A Partial List of Missing Features A Partial List of Missing Features
================================== ==================================
...@@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in ...@@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in
fs/cifs/connect.c and add back in NTLMSSP code if any servers fs/cifs/connect.c and add back in NTLMSSP code if any servers
need it need it
e) ms-dfs and ms-dfs host name resolution cleanup e) fix NTLMv2 signing when two mounts with different users to same
f) fix NTLMv2 signing when two mounts with different users to same
server. 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) 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) 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 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 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. extra copy in/out of the socket buffers in some cases.
......
...@@ -161,77 +161,108 @@ static void cifs_unix_info_to_inode(struct inode *inode, ...@@ -161,77 +161,108 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock); 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, int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *full_path, struct super_block *sb, int xid) const unsigned char *full_path, struct super_block *sb, int xid)
{ {
int rc = 0; int rc = 0;
FILE_UNIX_BASIC_INFO findData; FILE_UNIX_BASIC_INFO find_data;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
bool is_dfs_referral = false; bool is_dfs_referral = false;
struct cifsInodeInfo *cifsInfo;
__u64 num_of_bytes;
__u64 end_of_file;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", full_path)); cFYI(1, ("Getting info on %s", full_path));
try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */ /* 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_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
/* dump_mem("\nUnixQPathInfo return data", &findData,
sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE && !is_dfs_referral) { if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true; 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 { num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
struct cifsInodeInfo *cifsInfo; end_of_file = le64_to_cpu(find_data.EndOfFile);
__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
__u64 end_of_file = le64_to_cpu(findData.EndOfFile);
/* get new inode */ /* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL) { if (*pinode == NULL) {
*pinode = new_inode(sb); rc = -ENOMEM;
if (*pinode == NULL) { goto cgiiu_exit;
rc = -ENOMEM;
goto cgiiu_exit;
}
/* Is an i_ino of zero legal? */
/* 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 (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode);
} }
/* 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)find_data.UniqueId;
inode = *pinode; if (sb->s_flags & MS_NOATIME)
cifsInfo = CIFS_I(inode); (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
cFYI(1, ("Old time %ld", cifsInfo->time)); insert_inode_hash(*pinode);
cifsInfo->time = jiffies; }
cFYI(1, ("New time %ld", cifsInfo->time));
/* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse, 1);
cifs_unix_info_to_inode(inode, &findData, 0); inode = *pinode;
cifsInfo = CIFS_I(inode);
cFYI(1, ("Old time %ld", cifsInfo->time));
cifsInfo->time = jiffies;
cFYI(1, ("New time %ld", cifsInfo->time));
/* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse, 1);
if (num_of_bytes < end_of_file) cifs_unix_info_to_inode(inode, &find_data, 0);
cFYI(1, ("allocation size less than end of file"));
cFYI(1, ("Size %ld and blocks %llu",
(unsigned long) inode->i_size,
(unsigned long long)inode->i_blocks));
cifs_set_ops(inode, is_dfs_referral); if (num_of_bytes < end_of_file)
} cFYI(1, ("allocation size less than end of file"));
cFYI(1, ("Size %ld and blocks %llu",
(unsigned long) inode->i_size,
(unsigned long long)inode->i_blocks));
cifs_set_ops(inode, is_dfs_referral);
cgiiu_exit: cgiiu_exit:
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment