mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	[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:
		
							parent
							
								
									89562b777c
								
							
						
					
					
						commit
						0e4bbde94f
					
				
					 4 changed files with 93 additions and 58 deletions
				
			
		|  | @ -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 | ||||
| ------------------------------------- | ||||
|  |  | |||
|  | @ -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 | ||||
| ------------ | ||||
|  |  | |||
							
								
								
									
										15
									
								
								fs/cifs/TODO
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								fs/cifs/TODO
									
										
									
									
									
								
							|  | @ -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. | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										133
									
								
								fs/cifs/inode.c
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								fs/cifs/inode.c
									
										
									
									
									
								
							|  | @ -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; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Steve French
						Steve French