[CIFS] Enable DFS support for Unix query path info
authorSteve French <sfrench@us.ibm.com>
Tue, 20 May 2008 19:50:46 +0000 (19:50 +0000)
committerSteve French <sfrench@us.ibm.com>
Tue, 20 May 2008 19:50:46 +0000 (19:50 +0000)
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>
fs/cifs/AUTHORS
fs/cifs/CHANGES
fs/cifs/TODO
fs/cifs/inode.c

index 8848e4d..9c136d7 100644 (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
 -------------------------------------
index 502a4c2..28e3d5c 100644 (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
 ------------
index 92c9fea..5aff46c 100644 (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.
 
index 9d9b56a..422d4e2 100644 (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);
+       }
+       num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
+       end_of_file = le64_to_cpu(find_data.EndOfFile);
 
-               /* get new inode */
+       /* get new inode */
+       if (*pinode == NULL) {
+               *pinode = new_inode(sb);
                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);
+                       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;
 
-               inode = *pinode;
-               cifsInfo = CIFS_I(inode);
+               if (sb->s_flags & MS_NOATIME)
+                       (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
 
-               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);
+               insert_inode_hash(*pinode);
+       }
 
-               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)
-                       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_unix_info_to_inode(inode, &find_data, 0);
 
-               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:
        return rc;
 }