diff options
author | Jeff Layton <jlayton@redhat.com> | 2008-10-22 13:57:01 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-10-23 00:50:17 -0400 |
commit | 8d281efb67463fe8aac8f6e10b31492fc218bf2b (patch) | |
tree | 72b5642a48725656f2d1edac506ab5d2152de648 /fs/cifs/inode.c | |
parent | 84210e9120a8c01a14379ba1f9a9b0f963641d94 (diff) |
cifs: fix unlinking of rename target when server doesn't support open file renames
cifs: fix unlinking of rename target when server doesn't support open file renames
The patch to make cifs_rename undoable broke renaming one file on top of
another when the server doesn't support busy file renames. Remove the
code that uses busy file renames to unlink the target file, and just
have it call cifs_unlink. If the rename of the source file fails, then
the unlink won't be undoable, but hopefully that's rare enough that it
won't be a problem.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 87 |
1 files changed, 8 insertions, 79 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8ac4eabc1f8b..d54fa8aeaea9 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1293,12 +1293,9 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
1293 | struct cifs_sb_info *cifs_sb_source; | 1293 | struct cifs_sb_info *cifs_sb_source; |
1294 | struct cifs_sb_info *cifs_sb_target; | 1294 | struct cifs_sb_info *cifs_sb_target; |
1295 | struct cifsTconInfo *tcon; | 1295 | struct cifsTconInfo *tcon; |
1296 | struct cifsInodeInfo *target_cinode; | ||
1297 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; | 1296 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; |
1298 | FILE_UNIX_BASIC_INFO *info_buf_target; | 1297 | FILE_UNIX_BASIC_INFO *info_buf_target; |
1299 | __u16 dstfid; | 1298 | int xid, rc, tmprc; |
1300 | int xid, rc, tmprc, oplock = 0; | ||
1301 | bool delete_already_pending; | ||
1302 | 1299 | ||
1303 | cifs_sb_target = CIFS_SB(target_dir->i_sb); | 1300 | cifs_sb_target = CIFS_SB(target_dir->i_sb); |
1304 | cifs_sb_source = CIFS_SB(source_dir->i_sb); | 1301 | cifs_sb_source = CIFS_SB(source_dir->i_sb); |
@@ -1348,104 +1345,36 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
1348 | } | 1345 | } |
1349 | 1346 | ||
1350 | info_buf_target = info_buf_source + 1; | 1347 | info_buf_target = info_buf_source + 1; |
1351 | rc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, | 1348 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, |
1352 | info_buf_source, | 1349 | info_buf_source, |
1353 | cifs_sb_source->local_nls, | 1350 | cifs_sb_source->local_nls, |
1354 | cifs_sb_source->mnt_cifs_flags & | 1351 | cifs_sb_source->mnt_cifs_flags & |
1355 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1352 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1356 | if (rc != 0) | 1353 | if (tmprc != 0) |
1357 | goto unlink_target; | 1354 | goto unlink_target; |
1358 | 1355 | ||
1359 | rc = CIFSSMBUnixQPathInfo(xid, tcon, | 1356 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, |
1360 | toName, info_buf_target, | 1357 | toName, info_buf_target, |
1361 | cifs_sb_target->local_nls, | 1358 | cifs_sb_target->local_nls, |
1362 | /* remap based on source sb */ | 1359 | /* remap based on source sb */ |
1363 | cifs_sb_source->mnt_cifs_flags & | 1360 | cifs_sb_source->mnt_cifs_flags & |
1364 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1361 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1365 | 1362 | ||
1366 | if (rc == 0 && (info_buf_source->UniqueId == | 1363 | if (tmprc == 0 && (info_buf_source->UniqueId == |
1367 | info_buf_target->UniqueId)) | 1364 | info_buf_target->UniqueId)) |
1368 | /* same file, POSIX says that this is a noop */ | 1365 | /* same file, POSIX says that this is a noop */ |
1369 | goto cifs_rename_exit; | 1366 | goto cifs_rename_exit; |
1370 | |||
1371 | rc = -EEXIST; | ||
1372 | } /* else ... BB we could add the same check for Windows by | 1367 | } /* else ... BB we could add the same check for Windows by |
1373 | checking the UniqueId via FILE_INTERNAL_INFO */ | 1368 | checking the UniqueId via FILE_INTERNAL_INFO */ |
1374 | 1369 | ||
1375 | if ((rc == -EACCES) || (rc == -EEXIST)) { | ||
1376 | unlink_target: | 1370 | unlink_target: |
1377 | /* don't bother if this is a negative dentry */ | 1371 | if ((rc == -EACCES) || (rc == -EEXIST)) { |
1378 | if (!target_dentry->d_inode) | 1372 | tmprc = cifs_unlink(target_dir, target_dentry); |
1379 | goto cifs_rename_exit; | ||
1380 | |||
1381 | target_cinode = CIFS_I(target_dentry->d_inode); | ||
1382 | |||
1383 | /* try to move the target out of the way */ | ||
1384 | tmprc = CIFSSMBOpen(xid, tcon, toName, FILE_OPEN, DELETE, | ||
1385 | CREATE_NOT_DIR, &dstfid, &oplock, NULL, | ||
1386 | cifs_sb_target->local_nls, | ||
1387 | cifs_sb_target->mnt_cifs_flags & | ||
1388 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1389 | if (tmprc) | 1373 | if (tmprc) |
1390 | goto cifs_rename_exit; | 1374 | goto cifs_rename_exit; |
1391 | 1375 | ||
1392 | /* rename the file to random name */ | ||
1393 | tmprc = CIFSSMBRenameOpenFile(xid, tcon, dstfid, NULL, | ||
1394 | cifs_sb_target->local_nls, | ||
1395 | cifs_sb_target->mnt_cifs_flags & | ||
1396 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1397 | |||
1398 | if (tmprc) | ||
1399 | goto close_target; | ||
1400 | |||
1401 | delete_already_pending = target_cinode->delete_pending; | ||
1402 | |||
1403 | if (!delete_already_pending) { | ||
1404 | /* set delete on close */ | ||
1405 | tmprc = CIFSSMBSetFileDisposition(xid, tcon, | ||
1406 | true, dstfid, | ||
1407 | current->tgid); | ||
1408 | /* | ||
1409 | * This hack is for broken samba servers, remove this | ||
1410 | * once more fixed ones are in the field. | ||
1411 | */ | ||
1412 | if (tmprc == -ENOENT) | ||
1413 | delete_already_pending = false; | ||
1414 | else if (tmprc) | ||
1415 | goto undo_target_rename; | ||
1416 | |||
1417 | target_cinode->delete_pending = true; | ||
1418 | } | ||
1419 | |||
1420 | |||
1421 | rc = cifs_do_rename(xid, source_dentry, fromName, | 1376 | rc = cifs_do_rename(xid, source_dentry, fromName, |
1422 | target_dentry, toName); | 1377 | target_dentry, toName); |
1423 | |||
1424 | if (rc == 0) | ||
1425 | goto close_target; | ||
1426 | |||
1427 | /* | ||
1428 | * after this point, we can't bother with error handling on | ||
1429 | * the undo's. This is best effort since we can't do anything | ||
1430 | * about failures here. | ||
1431 | */ | ||
1432 | if (!delete_already_pending) { | ||
1433 | tmprc = CIFSSMBSetFileDisposition(xid, tcon, | ||
1434 | false, dstfid, | ||
1435 | current->tgid); | ||
1436 | if (tmprc == 0) | ||
1437 | target_cinode->delete_pending = false; | ||
1438 | } | ||
1439 | |||
1440 | undo_target_rename: | ||
1441 | /* rename failed: undo target rename */ | ||
1442 | CIFSSMBRenameOpenFile(xid, tcon, dstfid, | ||
1443 | target_dentry->d_name.name, | ||
1444 | cifs_sb_target->local_nls, | ||
1445 | cifs_sb_target->mnt_cifs_flags & | ||
1446 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1447 | close_target: | ||
1448 | CIFSSMBClose(xid, tcon, dstfid); | ||
1449 | } | 1378 | } |
1450 | 1379 | ||
1451 | cifs_rename_exit: | 1380 | cifs_rename_exit: |