aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-05-20 15:50:46 -0400
committerSteve French <sfrench@us.ibm.com>2008-05-20 15:50:46 -0400
commit0e4bbde94fdc33f5b3d793166b21bf768ca3e098 (patch)
tree858cc58dcd5b49de3611826cf5e57ae5d54345ed /fs/cifs/inode.c
parent89562b777c50d100d1694db7b1b023279839b9ae (diff)
[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>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c117
1 files changed, 74 insertions, 43 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9d9b56a9c08e..422d4e219fa4 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -161,77 +161,108 @@ static void cifs_unix_info_to_inode(struct inode *inode,
161 spin_unlock(&inode->i_lock); 161 spin_unlock(&inode->i_lock);
162} 162}
163 163
164static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
165 struct super_block *sb)
166{
167 struct inode *pinode = NULL;
168
169 memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0);
170
171/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
172 __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
173 __u64 UniqueId = 0; */
174 pfnd_dat->LastStatusChange =
175 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
176 pfnd_dat->LastAccessTime =
177 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
178 pfnd_dat->LastModificationTime =
179 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
180 pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
181 pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
182 pfnd_dat->Nlinks = cpu_to_le64(2);
183 if (sb->s_root)
184 pinode = sb->s_root->d_inode;
185 if (pinode == NULL)
186 return;
187
188 /* fill in default values for the remaining based on root
189 inode since we can not query the server for this inode info */
190 pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
191 pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
192 pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
193 pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
194}
195
164int cifs_get_inode_info_unix(struct inode **pinode, 196int cifs_get_inode_info_unix(struct inode **pinode,
165 const unsigned char *full_path, struct super_block *sb, int xid) 197 const unsigned char *full_path, struct super_block *sb, int xid)
166{ 198{
167 int rc = 0; 199 int rc = 0;
168 FILE_UNIX_BASIC_INFO findData; 200 FILE_UNIX_BASIC_INFO find_data;
169 struct cifsTconInfo *pTcon; 201 struct cifsTconInfo *pTcon;
170 struct inode *inode; 202 struct inode *inode;
171 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 203 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
172 bool is_dfs_referral = false; 204 bool is_dfs_referral = false;
205 struct cifsInodeInfo *cifsInfo;
206 __u64 num_of_bytes;
207 __u64 end_of_file;
173 208
174 pTcon = cifs_sb->tcon; 209 pTcon = cifs_sb->tcon;
175 cFYI(1, ("Getting info on %s", full_path)); 210 cFYI(1, ("Getting info on %s", full_path));
176 211
177try_again_CIFSSMBUnixQPathInfo:
178 /* could have done a find first instead but this returns more info */ 212 /* could have done a find first instead but this returns more info */
179 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData, 213 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
180 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 214 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
181 CIFS_MOUNT_MAP_SPECIAL_CHR); 215 CIFS_MOUNT_MAP_SPECIAL_CHR);
182/* dump_mem("\nUnixQPathInfo return data", &findData,
183 sizeof(findData)); */
184 if (rc) { 216 if (rc) {
185 if (rc == -EREMOTE && !is_dfs_referral) { 217 if (rc == -EREMOTE && !is_dfs_referral) {
186 is_dfs_referral = true; 218 is_dfs_referral = true;
187 goto try_again_CIFSSMBUnixQPathInfo; 219 cERROR(1, ("DFS ref")); /* BB removeme BB */
220 /* for DFS, server does not give us real inode data */
221 fill_fake_finddataunix(&find_data, sb);
222 rc = 0;
188 } 223 }
189 goto cgiiu_exit; 224 }
190 } else { 225 num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
191 struct cifsInodeInfo *cifsInfo; 226 end_of_file = le64_to_cpu(find_data.EndOfFile);
192 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
193 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
194 227
195 /* get new inode */ 228 /* get new inode */
229 if (*pinode == NULL) {
230 *pinode = new_inode(sb);
196 if (*pinode == NULL) { 231 if (*pinode == NULL) {
197 *pinode = new_inode(sb); 232 rc = -ENOMEM;
198 if (*pinode == NULL) { 233 goto cgiiu_exit;
199 rc = -ENOMEM;
200 goto cgiiu_exit;
201 }
202 /* Is an i_ino of zero legal? */
203 /* Are there sanity checks we can use to ensure that
204 the server is really filling in that field? */
205 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
206 (*pinode)->i_ino =
207 (unsigned long)findData.UniqueId;
208 } /* note ino incremented to unique num in new_inode */
209 if (sb->s_flags & MS_NOATIME)
210 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
211
212 insert_inode_hash(*pinode);
213 } 234 }
235 /* Is an i_ino of zero legal? */
236 /* note ino incremented to unique num in new_inode */
237 /* Are there sanity checks we can use to ensure that
238 the server is really filling in that field? */
239 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
240 (*pinode)->i_ino = (unsigned long)find_data.UniqueId;
214 241
215 inode = *pinode; 242 if (sb->s_flags & MS_NOATIME)
216 cifsInfo = CIFS_I(inode); 243 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
217 244
218 cFYI(1, ("Old time %ld", cifsInfo->time)); 245 insert_inode_hash(*pinode);
219 cifsInfo->time = jiffies; 246 }
220 cFYI(1, ("New time %ld", cifsInfo->time));
221 /* this is ok to set on every inode revalidate */
222 atomic_set(&cifsInfo->inUse, 1);
223 247
224 cifs_unix_info_to_inode(inode, &findData, 0); 248 inode = *pinode;
249 cifsInfo = CIFS_I(inode);
225 250
251 cFYI(1, ("Old time %ld", cifsInfo->time));
252 cifsInfo->time = jiffies;
253 cFYI(1, ("New time %ld", cifsInfo->time));
254 /* this is ok to set on every inode revalidate */
255 atomic_set(&cifsInfo->inUse, 1);
226 256
227 if (num_of_bytes < end_of_file) 257 cifs_unix_info_to_inode(inode, &find_data, 0);
228 cFYI(1, ("allocation size less than end of file"));
229 cFYI(1, ("Size %ld and blocks %llu",
230 (unsigned long) inode->i_size,
231 (unsigned long long)inode->i_blocks));
232 258
233 cifs_set_ops(inode, is_dfs_referral); 259 if (num_of_bytes < end_of_file)
234 } 260 cFYI(1, ("allocation size less than end of file"));
261 cFYI(1, ("Size %ld and blocks %llu",
262 (unsigned long) inode->i_size,
263 (unsigned long long)inode->i_blocks));
264
265 cifs_set_ops(inode, is_dfs_referral);
235cgiiu_exit: 266cgiiu_exit:
236 return rc; 267 return rc;
237} 268}