diff options
author | Steve French <sfrench@us.ibm.com> | 2008-05-20 15:50:46 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-05-20 15:50:46 -0400 |
commit | 0e4bbde94fdc33f5b3d793166b21bf768ca3e098 (patch) | |
tree | 858cc58dcd5b49de3611826cf5e57ae5d54345ed /fs/cifs/inode.c | |
parent | 89562b777c50d100d1694db7b1b023279839b9ae (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.c | 117 |
1 files changed, 74 insertions, 43 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 9d9b56a9c08..422d4e219fa 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 | ||
164 | static 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 | |||
164 | int cifs_get_inode_info_unix(struct inode **pinode, | 196 | int 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 | ||
177 | try_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); | ||
235 | cgiiu_exit: | 266 | cgiiu_exit: |
236 | return rc; | 267 | return rc; |
237 | } | 268 | } |