[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: Igor Mammedov <niallain@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2008-05-20 19:50:46 +00:00
parent 89562b777c
commit 0e4bbde94f
4 changed files with 93 additions and 58 deletions

View file

@ -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
-------------------------------------

View file

@ -1,5 +1,7 @@
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
------------

View file

@ -1,4 +1,4 @@
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.

View file

@ -161,77 +161,108 @@ 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);
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL) {
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);
}
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);
cifs_unix_info_to_inode(inode, &findData, 0);
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);
}
num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
end_of_file = le64_to_cpu(find_data.EndOfFile);
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL) {
rc = -ENOMEM;
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)find_data.UniqueId;
if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode);
}
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);
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"));
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:
return rc;
}