diff options
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 448 |
1 files changed, 245 insertions, 203 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index ec4e9a2a12f8..a180265a10b5 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -133,108 +133,141 @@ cifs_bp_rename_retry: | |||
133 | return full_path; | 133 | return full_path; |
134 | } | 134 | } |
135 | 135 | ||
136 | /* | ||
137 | * Don't allow the separator character in a path component. | ||
138 | * The VFS will not allow "/", but "\" is allowed by posix. | ||
139 | */ | ||
140 | static int | ||
141 | check_name(struct dentry *direntry) | ||
142 | { | ||
143 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | ||
144 | int i; | ||
145 | |||
146 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { | ||
147 | for (i = 0; i < direntry->d_name.len; i++) { | ||
148 | if (direntry->d_name.name[i] == '\\') { | ||
149 | cFYI(1, "Invalid file name"); | ||
150 | return -EINVAL; | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | |||
136 | /* Inode operations in similar order to how they appear in Linux file fs.h */ | 158 | /* Inode operations in similar order to how they appear in Linux file fs.h */ |
137 | 159 | ||
138 | int | 160 | static int cifs_do_create(struct inode *inode, struct dentry *direntry, |
139 | cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | 161 | int xid, struct tcon_link *tlink, unsigned oflags, |
140 | struct nameidata *nd) | 162 | umode_t mode, __u32 *oplock, __u16 *fileHandle, |
163 | int *created) | ||
141 | { | 164 | { |
142 | int rc = -ENOENT; | 165 | int rc = -ENOENT; |
143 | int xid; | ||
144 | int create_options = CREATE_NOT_DIR; | 166 | int create_options = CREATE_NOT_DIR; |
145 | __u32 oplock = 0; | 167 | int desiredAccess; |
146 | int oflags; | 168 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
147 | /* | 169 | struct cifs_tcon *tcon = tlink_tcon(tlink); |
148 | * BB below access is probably too much for mknod to request | ||
149 | * but we have to do query and setpathinfo so requesting | ||
150 | * less could fail (unless we want to request getatr and setatr | ||
151 | * permissions (only). At least for POSIX we do not have to | ||
152 | * request so much. | ||
153 | */ | ||
154 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | ||
155 | __u16 fileHandle; | ||
156 | struct cifs_sb_info *cifs_sb; | ||
157 | struct tcon_link *tlink; | ||
158 | struct cifs_tcon *tcon; | ||
159 | char *full_path = NULL; | 170 | char *full_path = NULL; |
160 | FILE_ALL_INFO *buf = NULL; | 171 | FILE_ALL_INFO *buf = NULL; |
161 | struct inode *newinode = NULL; | 172 | struct inode *newinode = NULL; |
162 | int disposition = FILE_OVERWRITE_IF; | 173 | int disposition; |
163 | |||
164 | xid = GetXid(); | ||
165 | |||
166 | cifs_sb = CIFS_SB(inode->i_sb); | ||
167 | tlink = cifs_sb_tlink(cifs_sb); | ||
168 | if (IS_ERR(tlink)) { | ||
169 | FreeXid(xid); | ||
170 | return PTR_ERR(tlink); | ||
171 | } | ||
172 | tcon = tlink_tcon(tlink); | ||
173 | 174 | ||
175 | *oplock = 0; | ||
174 | if (tcon->ses->server->oplocks) | 176 | if (tcon->ses->server->oplocks) |
175 | oplock = REQ_OPLOCK; | 177 | *oplock = REQ_OPLOCK; |
176 | |||
177 | if (nd) | ||
178 | oflags = nd->intent.open.file->f_flags; | ||
179 | else | ||
180 | oflags = O_RDONLY | O_CREAT; | ||
181 | 178 | ||
182 | full_path = build_path_from_dentry(direntry); | 179 | full_path = build_path_from_dentry(direntry); |
183 | if (full_path == NULL) { | 180 | if (full_path == NULL) { |
184 | rc = -ENOMEM; | 181 | rc = -ENOMEM; |
185 | goto cifs_create_out; | 182 | goto out; |
186 | } | 183 | } |
187 | 184 | ||
188 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 185 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
186 | !tcon->broken_posix_open && | ||
189 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 187 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
190 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 188 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
191 | rc = cifs_posix_open(full_path, &newinode, | 189 | rc = cifs_posix_open(full_path, &newinode, |
192 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); | 190 | inode->i_sb, mode, oflags, oplock, fileHandle, xid); |
193 | /* EIO could indicate that (posix open) operation is not | 191 | switch (rc) { |
194 | supported, despite what server claimed in capability | 192 | case 0: |
195 | negotiation. EREMOTE indicates DFS junction, which is not | 193 | if (newinode == NULL) { |
196 | handled in posix open */ | 194 | /* query inode info */ |
197 | |||
198 | if (rc == 0) { | ||
199 | if (newinode == NULL) /* query inode info */ | ||
200 | goto cifs_create_get_file_info; | 195 | goto cifs_create_get_file_info; |
201 | else /* success, no need to query */ | 196 | } |
202 | goto cifs_create_set_dentry; | 197 | |
203 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | 198 | if (!S_ISREG(newinode->i_mode)) { |
204 | (rc != -EOPNOTSUPP) && (rc != -EINVAL)) | 199 | /* |
205 | goto cifs_create_out; | 200 | * The server may allow us to open things like |
206 | /* else fallthrough to retry, using older open call, this is | 201 | * FIFOs, but the client isn't set up to deal |
207 | case where server does not support this SMB level, and | 202 | * with that. If it's not a regular file, just |
208 | falsely claims capability (also get here for DFS case | 203 | * close it and proceed as if it were a normal |
209 | which should be rare for path not covered on files) */ | 204 | * lookup. |
210 | } | 205 | */ |
206 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
207 | goto cifs_create_get_file_info; | ||
208 | } | ||
209 | /* success, no need to query */ | ||
210 | goto cifs_create_set_dentry; | ||
211 | |||
212 | case -ENOENT: | ||
213 | goto cifs_create_get_file_info; | ||
214 | |||
215 | case -EIO: | ||
216 | case -EINVAL: | ||
217 | /* | ||
218 | * EIO could indicate that (posix open) operation is not | ||
219 | * supported, despite what server claimed in capability | ||
220 | * negotiation. | ||
221 | * | ||
222 | * POSIX open in samba versions 3.3.1 and earlier could | ||
223 | * incorrectly fail with invalid parameter. | ||
224 | */ | ||
225 | tcon->broken_posix_open = true; | ||
226 | break; | ||
227 | |||
228 | case -EREMOTE: | ||
229 | case -EOPNOTSUPP: | ||
230 | /* | ||
231 | * EREMOTE indicates DFS junction, which is not handled | ||
232 | * in posix open. If either that or op not supported | ||
233 | * returned, follow the normal lookup. | ||
234 | */ | ||
235 | break; | ||
211 | 236 | ||
212 | if (nd) { | 237 | default: |
213 | /* if the file is going to stay open, then we | 238 | goto out; |
214 | need to set the desired access properly */ | 239 | } |
215 | desiredAccess = 0; | 240 | /* |
216 | if (OPEN_FMODE(oflags) & FMODE_READ) | 241 | * fallthrough to retry, using older open call, this is case |
217 | desiredAccess |= GENERIC_READ; /* is this too little? */ | 242 | * where server does not support this SMB level, and falsely |
218 | if (OPEN_FMODE(oflags) & FMODE_WRITE) | 243 | * claims capability (also get here for DFS case which should be |
219 | desiredAccess |= GENERIC_WRITE; | 244 | * rare for path not covered on files) |
220 | 245 | */ | |
221 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
222 | disposition = FILE_CREATE; | ||
223 | else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
224 | disposition = FILE_OVERWRITE_IF; | ||
225 | else if ((oflags & O_CREAT) == O_CREAT) | ||
226 | disposition = FILE_OPEN_IF; | ||
227 | else | ||
228 | cFYI(1, "Create flag not set in create function"); | ||
229 | } | 246 | } |
230 | 247 | ||
248 | desiredAccess = 0; | ||
249 | if (OPEN_FMODE(oflags) & FMODE_READ) | ||
250 | desiredAccess |= GENERIC_READ; /* is this too little? */ | ||
251 | if (OPEN_FMODE(oflags) & FMODE_WRITE) | ||
252 | desiredAccess |= GENERIC_WRITE; | ||
253 | |||
254 | disposition = FILE_OVERWRITE_IF; | ||
255 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
256 | disposition = FILE_CREATE; | ||
257 | else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
258 | disposition = FILE_OVERWRITE_IF; | ||
259 | else if ((oflags & O_CREAT) == O_CREAT) | ||
260 | disposition = FILE_OPEN_IF; | ||
261 | else | ||
262 | cFYI(1, "Create flag not set in create function"); | ||
263 | |||
231 | /* BB add processing to set equivalent of mode - e.g. via CreateX with | 264 | /* BB add processing to set equivalent of mode - e.g. via CreateX with |
232 | ACLs */ | 265 | ACLs */ |
233 | 266 | ||
234 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 267 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
235 | if (buf == NULL) { | 268 | if (buf == NULL) { |
236 | rc = -ENOMEM; | 269 | rc = -ENOMEM; |
237 | goto cifs_create_out; | 270 | goto out; |
238 | } | 271 | } |
239 | 272 | ||
240 | /* | 273 | /* |
@@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
250 | if (tcon->ses->capabilities & CAP_NT_SMBS) | 283 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
251 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 284 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
252 | desiredAccess, create_options, | 285 | desiredAccess, create_options, |
253 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 286 | fileHandle, oplock, buf, cifs_sb->local_nls, |
254 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 287 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
255 | else | 288 | else |
256 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | 289 | rc = -EIO; /* no NT SMB support fall into legacy open below */ |
@@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
259 | /* old server, retry the open legacy style */ | 292 | /* old server, retry the open legacy style */ |
260 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | 293 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, |
261 | desiredAccess, create_options, | 294 | desiredAccess, create_options, |
262 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 295 | fileHandle, oplock, buf, cifs_sb->local_nls, |
263 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 296 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
264 | } | 297 | } |
265 | if (rc) { | 298 | if (rc) { |
266 | cFYI(1, "cifs_create returned 0x%x", rc); | 299 | cFYI(1, "cifs_create returned 0x%x", rc); |
267 | goto cifs_create_out; | 300 | goto out; |
268 | } | 301 | } |
269 | 302 | ||
270 | /* If Open reported that we actually created a file | 303 | /* If Open reported that we actually created a file |
271 | then we now have to set the mode if possible */ | 304 | then we now have to set the mode if possible */ |
272 | if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { | 305 | if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) { |
273 | struct cifs_unix_set_info_args args = { | 306 | struct cifs_unix_set_info_args args = { |
274 | .mode = mode, | 307 | .mode = mode, |
275 | .ctime = NO_CHANGE_64, | 308 | .ctime = NO_CHANGE_64, |
@@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
278 | .device = 0, | 311 | .device = 0, |
279 | }; | 312 | }; |
280 | 313 | ||
314 | *created |= FILE_CREATED; | ||
281 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 315 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
282 | args.uid = (__u64) current_fsuid(); | 316 | args.uid = (__u64) current_fsuid(); |
283 | if (inode->i_mode & S_ISGID) | 317 | if (inode->i_mode & S_ISGID) |
@@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
288 | args.uid = NO_CHANGE_64; | 322 | args.uid = NO_CHANGE_64; |
289 | args.gid = NO_CHANGE_64; | 323 | args.gid = NO_CHANGE_64; |
290 | } | 324 | } |
291 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, | 325 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle, |
292 | current->tgid); | 326 | current->tgid); |
293 | } else { | 327 | } else { |
294 | /* BB implement mode setting via Windows security | 328 | /* BB implement mode setting via Windows security |
@@ -305,11 +339,11 @@ cifs_create_get_file_info: | |||
305 | inode->i_sb, xid); | 339 | inode->i_sb, xid); |
306 | else { | 340 | else { |
307 | rc = cifs_get_inode_info(&newinode, full_path, buf, | 341 | rc = cifs_get_inode_info(&newinode, full_path, buf, |
308 | inode->i_sb, xid, &fileHandle); | 342 | inode->i_sb, xid, fileHandle); |
309 | if (newinode) { | 343 | if (newinode) { |
310 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | 344 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
311 | newinode->i_mode = mode; | 345 | newinode->i_mode = mode; |
312 | if ((oplock & CIFS_CREATE_ACTION) && | 346 | if ((*oplock & CIFS_CREATE_ACTION) && |
313 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { | 347 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { |
314 | newinode->i_uid = current_fsuid(); | 348 | newinode->i_uid = current_fsuid(); |
315 | if (inode->i_mode & S_ISGID) | 349 | if (inode->i_mode & S_ISGID) |
@@ -321,40 +355,139 @@ cifs_create_get_file_info: | |||
321 | } | 355 | } |
322 | 356 | ||
323 | cifs_create_set_dentry: | 357 | cifs_create_set_dentry: |
324 | if (rc == 0) | 358 | if (rc != 0) { |
325 | d_instantiate(direntry, newinode); | ||
326 | else | ||
327 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 359 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
360 | goto out; | ||
361 | } | ||
362 | d_drop(direntry); | ||
363 | d_add(direntry, newinode); | ||
328 | 364 | ||
329 | if (newinode && nd) { | 365 | /* ENOENT for create? How weird... */ |
330 | struct cifsFileInfo *pfile_info; | 366 | rc = -ENOENT; |
331 | struct file *filp; | 367 | if (!newinode) { |
368 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
369 | goto out; | ||
370 | } | ||
371 | rc = 0; | ||
332 | 372 | ||
333 | filp = lookup_instantiate_filp(nd, direntry, generic_file_open); | 373 | out: |
334 | if (IS_ERR(filp)) { | 374 | kfree(buf); |
335 | rc = PTR_ERR(filp); | 375 | kfree(full_path); |
336 | CIFSSMBClose(xid, tcon, fileHandle); | 376 | return rc; |
337 | goto cifs_create_out; | 377 | } |
338 | } | ||
339 | 378 | ||
340 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); | 379 | int |
341 | if (pfile_info == NULL) { | 380 | cifs_atomic_open(struct inode *inode, struct dentry *direntry, |
342 | fput(filp); | 381 | struct file *file, unsigned oflags, umode_t mode, |
343 | CIFSSMBClose(xid, tcon, fileHandle); | 382 | int *opened) |
344 | rc = -ENOMEM; | 383 | { |
345 | } | 384 | int rc; |
346 | } else { | 385 | int xid; |
386 | struct tcon_link *tlink; | ||
387 | struct cifs_tcon *tcon; | ||
388 | __u16 fileHandle; | ||
389 | __u32 oplock; | ||
390 | struct file *filp; | ||
391 | struct cifsFileInfo *pfile_info; | ||
392 | |||
393 | /* Posix open is only called (at lookup time) for file create now. For | ||
394 | * opens (rather than creates), because we do not know if it is a file | ||
395 | * or directory yet, and current Samba no longer allows us to do posix | ||
396 | * open on dirs, we could end up wasting an open call on what turns out | ||
397 | * to be a dir. For file opens, we wait to call posix open till | ||
398 | * cifs_open. It could be added to atomic_open in the future but the | ||
399 | * performance tradeoff of the extra network request when EISDIR or | ||
400 | * EACCES is returned would have to be weighed against the 50% reduction | ||
401 | * in network traffic in the other paths. | ||
402 | */ | ||
403 | if (!(oflags & O_CREAT)) { | ||
404 | struct dentry *res = cifs_lookup(inode, direntry, 0); | ||
405 | if (IS_ERR(res)) | ||
406 | return PTR_ERR(res); | ||
407 | |||
408 | return finish_no_open(file, res); | ||
409 | } | ||
410 | |||
411 | rc = check_name(direntry); | ||
412 | if (rc) | ||
413 | return rc; | ||
414 | |||
415 | xid = GetXid(); | ||
416 | |||
417 | cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
418 | inode, direntry->d_name.name, direntry); | ||
419 | |||
420 | tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); | ||
421 | filp = ERR_CAST(tlink); | ||
422 | if (IS_ERR(tlink)) | ||
423 | goto free_xid; | ||
424 | |||
425 | tcon = tlink_tcon(tlink); | ||
426 | |||
427 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | ||
428 | &oplock, &fileHandle, opened); | ||
429 | |||
430 | if (rc) | ||
431 | goto out; | ||
432 | |||
433 | rc = finish_open(file, direntry, generic_file_open, opened); | ||
434 | if (rc) { | ||
347 | CIFSSMBClose(xid, tcon, fileHandle); | 435 | CIFSSMBClose(xid, tcon, fileHandle); |
436 | goto out; | ||
348 | } | 437 | } |
349 | 438 | ||
350 | cifs_create_out: | 439 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); |
351 | kfree(buf); | 440 | if (pfile_info == NULL) { |
352 | kfree(full_path); | 441 | CIFSSMBClose(xid, tcon, fileHandle); |
442 | fput(filp); | ||
443 | rc = -ENOMEM; | ||
444 | } | ||
445 | |||
446 | out: | ||
353 | cifs_put_tlink(tlink); | 447 | cifs_put_tlink(tlink); |
448 | free_xid: | ||
354 | FreeXid(xid); | 449 | FreeXid(xid); |
355 | return rc; | 450 | return rc; |
356 | } | 451 | } |
357 | 452 | ||
453 | int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | ||
454 | bool excl) | ||
455 | { | ||
456 | int rc; | ||
457 | int xid = GetXid(); | ||
458 | /* | ||
459 | * BB below access is probably too much for mknod to request | ||
460 | * but we have to do query and setpathinfo so requesting | ||
461 | * less could fail (unless we want to request getatr and setatr | ||
462 | * permissions (only). At least for POSIX we do not have to | ||
463 | * request so much. | ||
464 | */ | ||
465 | unsigned oflags = O_EXCL | O_CREAT | O_RDWR; | ||
466 | struct tcon_link *tlink; | ||
467 | __u16 fileHandle; | ||
468 | __u32 oplock; | ||
469 | int created = FILE_CREATED; | ||
470 | |||
471 | cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
472 | inode, direntry->d_name.name, direntry); | ||
473 | |||
474 | tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); | ||
475 | rc = PTR_ERR(tlink); | ||
476 | if (IS_ERR(tlink)) | ||
477 | goto free_xid; | ||
478 | |||
479 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | ||
480 | &oplock, &fileHandle, &created); | ||
481 | if (!rc) | ||
482 | CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle); | ||
483 | |||
484 | cifs_put_tlink(tlink); | ||
485 | free_xid: | ||
486 | FreeXid(xid); | ||
487 | |||
488 | return rc; | ||
489 | } | ||
490 | |||
358 | int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, | 491 | int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, |
359 | dev_t device_number) | 492 | dev_t device_number) |
360 | { | 493 | { |
@@ -488,20 +621,15 @@ mknod_out: | |||
488 | 621 | ||
489 | struct dentry * | 622 | struct dentry * |
490 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | 623 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, |
491 | struct nameidata *nd) | 624 | unsigned int flags) |
492 | { | 625 | { |
493 | int xid; | 626 | int xid; |
494 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | 627 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
495 | __u32 oplock; | ||
496 | __u16 fileHandle = 0; | ||
497 | bool posix_open = false; | ||
498 | struct cifs_sb_info *cifs_sb; | 628 | struct cifs_sb_info *cifs_sb; |
499 | struct tcon_link *tlink; | 629 | struct tcon_link *tlink; |
500 | struct cifs_tcon *pTcon; | 630 | struct cifs_tcon *pTcon; |
501 | struct cifsFileInfo *cfile; | ||
502 | struct inode *newInode = NULL; | 631 | struct inode *newInode = NULL; |
503 | char *full_path = NULL; | 632 | char *full_path = NULL; |
504 | struct file *filp; | ||
505 | 633 | ||
506 | xid = GetXid(); | 634 | xid = GetXid(); |
507 | 635 | ||
@@ -518,31 +646,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
518 | } | 646 | } |
519 | pTcon = tlink_tcon(tlink); | 647 | pTcon = tlink_tcon(tlink); |
520 | 648 | ||
521 | oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; | 649 | rc = check_name(direntry); |
522 | 650 | if (rc) | |
523 | /* | ||
524 | * Don't allow the separator character in a path component. | ||
525 | * The VFS will not allow "/", but "\" is allowed by posix. | ||
526 | */ | ||
527 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { | ||
528 | int i; | ||
529 | for (i = 0; i < direntry->d_name.len; i++) | ||
530 | if (direntry->d_name.name[i] == '\\') { | ||
531 | cFYI(1, "Invalid file name"); | ||
532 | rc = -EINVAL; | ||
533 | goto lookup_out; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let | ||
539 | * the VFS handle the create. | ||
540 | */ | ||
541 | if (nd && (nd->flags & LOOKUP_EXCL)) { | ||
542 | d_instantiate(direntry, NULL); | ||
543 | rc = 0; | ||
544 | goto lookup_out; | 651 | goto lookup_out; |
545 | } | ||
546 | 652 | ||
547 | /* can not grab the rename sem here since it would | 653 | /* can not grab the rename sem here since it would |
548 | deadlock in the cases (beginning of sys_rename itself) | 654 | deadlock in the cases (beginning of sys_rename itself) |
@@ -560,80 +666,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
560 | } | 666 | } |
561 | cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); | 667 | cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); |
562 | 668 | ||
563 | /* Posix open is only called (at lookup time) for file create now. | ||
564 | * For opens (rather than creates), because we do not know if it | ||
565 | * is a file or directory yet, and current Samba no longer allows | ||
566 | * us to do posix open on dirs, we could end up wasting an open call | ||
567 | * on what turns out to be a dir. For file opens, we wait to call posix | ||
568 | * open till cifs_open. It could be added here (lookup) in the future | ||
569 | * but the performance tradeoff of the extra network request when EISDIR | ||
570 | * or EACCES is returned would have to be weighed against the 50% | ||
571 | * reduction in network traffic in the other paths. | ||
572 | */ | ||
573 | if (pTcon->unix_ext) { | 669 | if (pTcon->unix_ext) { |
574 | if (nd && !(nd->flags & LOOKUP_DIRECTORY) && | 670 | rc = cifs_get_inode_info_unix(&newInode, full_path, |
575 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 671 | parent_dir_inode->i_sb, xid); |
576 | (nd->intent.open.file->f_flags & O_CREAT)) { | 672 | } else { |
577 | rc = cifs_posix_open(full_path, &newInode, | ||
578 | parent_dir_inode->i_sb, | ||
579 | nd->intent.open.create_mode, | ||
580 | nd->intent.open.file->f_flags, &oplock, | ||
581 | &fileHandle, xid); | ||
582 | /* | ||
583 | * The check below works around a bug in POSIX | ||
584 | * open in samba versions 3.3.1 and earlier where | ||
585 | * open could incorrectly fail with invalid parameter. | ||
586 | * If either that or op not supported returned, follow | ||
587 | * the normal lookup. | ||
588 | */ | ||
589 | switch (rc) { | ||
590 | case 0: | ||
591 | /* | ||
592 | * The server may allow us to open things like | ||
593 | * FIFOs, but the client isn't set up to deal | ||
594 | * with that. If it's not a regular file, just | ||
595 | * close it and proceed as if it were a normal | ||
596 | * lookup. | ||
597 | */ | ||
598 | if (newInode && !S_ISREG(newInode->i_mode)) { | ||
599 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
600 | break; | ||
601 | } | ||
602 | case -ENOENT: | ||
603 | posix_open = true; | ||
604 | case -EOPNOTSUPP: | ||
605 | break; | ||
606 | default: | ||
607 | pTcon->broken_posix_open = true; | ||
608 | } | ||
609 | } | ||
610 | if (!posix_open) | ||
611 | rc = cifs_get_inode_info_unix(&newInode, full_path, | ||
612 | parent_dir_inode->i_sb, xid); | ||
613 | } else | ||
614 | rc = cifs_get_inode_info(&newInode, full_path, NULL, | 673 | rc = cifs_get_inode_info(&newInode, full_path, NULL, |
615 | parent_dir_inode->i_sb, xid, NULL); | 674 | parent_dir_inode->i_sb, xid, NULL); |
675 | } | ||
616 | 676 | ||
617 | if ((rc == 0) && (newInode != NULL)) { | 677 | if ((rc == 0) && (newInode != NULL)) { |
618 | d_add(direntry, newInode); | 678 | d_add(direntry, newInode); |
619 | if (posix_open) { | ||
620 | filp = lookup_instantiate_filp(nd, direntry, | ||
621 | generic_file_open); | ||
622 | if (IS_ERR(filp)) { | ||
623 | rc = PTR_ERR(filp); | ||
624 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
625 | goto lookup_out; | ||
626 | } | ||
627 | |||
628 | cfile = cifs_new_fileinfo(fileHandle, filp, tlink, | ||
629 | oplock); | ||
630 | if (cfile == NULL) { | ||
631 | fput(filp); | ||
632 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
633 | rc = -ENOMEM; | ||
634 | goto lookup_out; | ||
635 | } | ||
636 | } | ||
637 | /* since paths are not looked up by component - the parent | 679 | /* since paths are not looked up by component - the parent |
638 | directories are presumed to be good here */ | 680 | directories are presumed to be good here */ |
639 | renew_parental_timestamps(direntry); | 681 | renew_parental_timestamps(direntry); |
@@ -658,9 +700,9 @@ lookup_out: | |||
658 | } | 700 | } |
659 | 701 | ||
660 | static int | 702 | static int |
661 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | 703 | cifs_d_revalidate(struct dentry *direntry, unsigned int flags) |
662 | { | 704 | { |
663 | if (nd && (nd->flags & LOOKUP_RCU)) | 705 | if (flags & LOOKUP_RCU) |
664 | return -ECHILD; | 706 | return -ECHILD; |
665 | 707 | ||
666 | if (direntry->d_inode) { | 708 | if (direntry->d_inode) { |
@@ -689,7 +731,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
689 | * This may be nfsd (or something), anyway, we can't see the | 731 | * This may be nfsd (or something), anyway, we can't see the |
690 | * intent of this. So, since this can be for creation, drop it. | 732 | * intent of this. So, since this can be for creation, drop it. |
691 | */ | 733 | */ |
692 | if (!nd) | 734 | if (!flags) |
693 | return 0; | 735 | return 0; |
694 | 736 | ||
695 | /* | 737 | /* |
@@ -697,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
697 | * case sensitive name which is specified by user if this is | 739 | * case sensitive name which is specified by user if this is |
698 | * for creation. | 740 | * for creation. |
699 | */ | 741 | */ |
700 | if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) | 742 | if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) |
701 | return 0; | 743 | return 0; |
702 | 744 | ||
703 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) | 745 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) |