aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c211
1 files changed, 127 insertions, 84 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a8c833345fc9..d54fa8aeaea9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -506,6 +506,7 @@ int cifs_get_inode_info(struct inode **pinode,
506 inode = *pinode; 506 inode = *pinode;
507 cifsInfo = CIFS_I(inode); 507 cifsInfo = CIFS_I(inode);
508 cifsInfo->cifsAttrs = attr; 508 cifsInfo->cifsAttrs = attr;
509 cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
509 cFYI(1, ("Old time %ld", cifsInfo->time)); 510 cFYI(1, ("Old time %ld", cifsInfo->time));
510 cifsInfo->time = jiffies; 511 cifsInfo->time = jiffies;
511 cFYI(1, ("New time %ld", cifsInfo->time)); 512 cFYI(1, ("New time %ld", cifsInfo->time));
@@ -772,63 +773,106 @@ out:
772 * anything else. 773 * anything else.
773 */ 774 */
774static int 775static int
775cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid) 776cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
776{ 777{
777 int oplock = 0; 778 int oplock = 0;
778 int rc; 779 int rc;
779 __u16 netfid; 780 __u16 netfid;
781 struct inode *inode = dentry->d_inode;
780 struct cifsInodeInfo *cifsInode = CIFS_I(inode); 782 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
781 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 783 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
782 struct cifsTconInfo *tcon = cifs_sb->tcon; 784 struct cifsTconInfo *tcon = cifs_sb->tcon;
783 __u32 dosattr; 785 __u32 dosattr, origattr;
784 FILE_BASIC_INFO *info_buf; 786 FILE_BASIC_INFO *info_buf = NULL;
785 787
786 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, 788 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
787 DELETE|FILE_WRITE_ATTRIBUTES, 789 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
788 CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE,
789 &netfid, &oplock, NULL, cifs_sb->local_nls, 790 &netfid, &oplock, NULL, cifs_sb->local_nls,
790 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 791 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
791 if (rc != 0) 792 if (rc != 0)
792 goto out; 793 goto out;
793 794
794 /* set ATTR_HIDDEN and clear ATTR_READONLY */ 795 origattr = cifsInode->cifsAttrs;
795 cifsInode = CIFS_I(inode); 796 if (origattr == 0)
796 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; 797 origattr |= ATTR_NORMAL;
798
799 dosattr = origattr & ~ATTR_READONLY;
797 if (dosattr == 0) 800 if (dosattr == 0)
798 dosattr |= ATTR_NORMAL; 801 dosattr |= ATTR_NORMAL;
799 dosattr |= ATTR_HIDDEN; 802 dosattr |= ATTR_HIDDEN;
800 803
801 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); 804 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
802 if (info_buf == NULL) { 805 if (dosattr != origattr) {
803 rc = -ENOMEM; 806 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
804 goto out_close; 807 if (info_buf == NULL) {
808 rc = -ENOMEM;
809 goto out_close;
810 }
811 info_buf->Attributes = cpu_to_le32(dosattr);
812 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
813 current->tgid);
814 /* although we would like to mark the file hidden
815 if that fails we will still try to rename it */
816 if (rc != 0)
817 cifsInode->cifsAttrs = dosattr;
818 else
819 dosattr = origattr; /* since not able to change them */
805 } 820 }
806 info_buf->Attributes = cpu_to_le32(dosattr);
807 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
808 kfree(info_buf);
809 if (rc != 0)
810 goto out_close;
811 cifsInode->cifsAttrs = dosattr;
812 821
813 /* silly-rename the file */ 822 /* rename the file */
814 CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, 823 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
815 cifs_sb->mnt_cifs_flags & 824 cifs_sb->mnt_cifs_flags &
816 CIFS_MOUNT_MAP_SPECIAL_CHR); 825 CIFS_MOUNT_MAP_SPECIAL_CHR);
826 if (rc != 0) {
827 rc = -ETXTBSY;
828 goto undo_setattr;
829 }
817 830
818 /* set DELETE_ON_CLOSE */ 831 /* try to set DELETE_ON_CLOSE */
819 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid); 832 if (!cifsInode->delete_pending) {
820 833 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
821 /* 834 current->tgid);
822 * some samba versions return -ENOENT when we try to set the file 835 /*
823 * disposition here. Likely a samba bug, but work around it for now 836 * some samba versions return -ENOENT when we try to set the
824 */ 837 * file disposition here. Likely a samba bug, but work around
825 if (rc == -ENOENT) 838 * it for now. This means that some cifsXXX files may hang
826 rc = 0; 839 * around after they shouldn't.
840 *
841 * BB: remove this hack after more servers have the fix
842 */
843 if (rc == -ENOENT)
844 rc = 0;
845 else if (rc != 0) {
846 rc = -ETXTBSY;
847 goto undo_rename;
848 }
849 cifsInode->delete_pending = true;
850 }
827 851
828out_close: 852out_close:
829 CIFSSMBClose(xid, tcon, netfid); 853 CIFSSMBClose(xid, tcon, netfid);
830out: 854out:
855 kfree(info_buf);
831 return rc; 856 return rc;
857
858 /*
859 * reset everything back to the original state. Don't bother
860 * dealing with errors here since we can't do anything about
861 * them anyway.
862 */
863undo_rename:
864 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
865 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
866 CIFS_MOUNT_MAP_SPECIAL_CHR);
867undo_setattr:
868 if (dosattr != origattr) {
869 info_buf->Attributes = cpu_to_le32(origattr);
870 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
871 current->tgid))
872 cifsInode->cifsAttrs = origattr;
873 }
874
875 goto out_close;
832} 876}
833 877
834int cifs_unlink(struct inode *dir, struct dentry *dentry) 878int cifs_unlink(struct inode *dir, struct dentry *dentry)
@@ -878,7 +922,7 @@ psx_del_no_retry:
878 } else if (rc == -ENOENT) { 922 } else if (rc == -ENOENT) {
879 d_drop(dentry); 923 d_drop(dentry);
880 } else if (rc == -ETXTBSY) { 924 } else if (rc == -ETXTBSY) {
881 rc = cifs_rename_pending_delete(full_path, inode, xid); 925 rc = cifs_rename_pending_delete(full_path, dentry, xid);
882 if (rc == 0) 926 if (rc == 0)
883 drop_nlink(inode); 927 drop_nlink(inode);
884 } else if (rc == -EACCES && dosattr == 0) { 928 } else if (rc == -EACCES && dosattr == 0) {
@@ -1241,22 +1285,21 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1241 return rc; 1285 return rc;
1242} 1286}
1243 1287
1244int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, 1288int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1245 struct inode *target_inode, struct dentry *target_direntry) 1289 struct inode *target_dir, struct dentry *target_dentry)
1246{ 1290{
1247 char *fromName = NULL; 1291 char *fromName = NULL;
1248 char *toName = NULL; 1292 char *toName = NULL;
1249 struct cifs_sb_info *cifs_sb_source; 1293 struct cifs_sb_info *cifs_sb_source;
1250 struct cifs_sb_info *cifs_sb_target; 1294 struct cifs_sb_info *cifs_sb_target;
1251 struct cifsTconInfo *pTcon; 1295 struct cifsTconInfo *tcon;
1252 FILE_UNIX_BASIC_INFO *info_buf_source = NULL; 1296 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1253 FILE_UNIX_BASIC_INFO *info_buf_target; 1297 FILE_UNIX_BASIC_INFO *info_buf_target;
1254 int xid; 1298 int xid, rc, tmprc;
1255 int rc;
1256 1299
1257 cifs_sb_target = CIFS_SB(target_inode->i_sb); 1300 cifs_sb_target = CIFS_SB(target_dir->i_sb);
1258 cifs_sb_source = CIFS_SB(source_inode->i_sb); 1301 cifs_sb_source = CIFS_SB(source_dir->i_sb);
1259 pTcon = cifs_sb_source->tcon; 1302 tcon = cifs_sb_source->tcon;
1260 1303
1261 xid = GetXid(); 1304 xid = GetXid();
1262 1305
@@ -1264,7 +1307,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1264 * BB: this might be allowed if same server, but different share. 1307 * BB: this might be allowed if same server, but different share.
1265 * Consider adding support for this 1308 * Consider adding support for this
1266 */ 1309 */
1267 if (pTcon != cifs_sb_target->tcon) { 1310 if (tcon != cifs_sb_target->tcon) {
1268 rc = -EXDEV; 1311 rc = -EXDEV;
1269 goto cifs_rename_exit; 1312 goto cifs_rename_exit;
1270 } 1313 }
@@ -1273,65 +1316,65 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1273 * we already have the rename sem so we do not need to 1316 * we already have the rename sem so we do not need to
1274 * grab it again here to protect the path integrity 1317 * grab it again here to protect the path integrity
1275 */ 1318 */
1276 fromName = build_path_from_dentry(source_direntry); 1319 fromName = build_path_from_dentry(source_dentry);
1277 if (fromName == NULL) { 1320 if (fromName == NULL) {
1278 rc = -ENOMEM; 1321 rc = -ENOMEM;
1279 goto cifs_rename_exit; 1322 goto cifs_rename_exit;
1280 } 1323 }
1281 1324
1282 toName = build_path_from_dentry(target_direntry); 1325 toName = build_path_from_dentry(target_dentry);
1283 if (toName == NULL) { 1326 if (toName == NULL) {
1284 rc = -ENOMEM; 1327 rc = -ENOMEM;
1285 goto cifs_rename_exit; 1328 goto cifs_rename_exit;
1286 } 1329 }
1287 1330
1288 rc = cifs_do_rename(xid, source_direntry, fromName, 1331 rc = cifs_do_rename(xid, source_dentry, fromName,
1289 target_direntry, toName); 1332 target_dentry, toName);
1290 1333
1291 if (rc == -EEXIST) { 1334 if (rc == -EEXIST && tcon->unix_ext) {
1292 if (pTcon->unix_ext) { 1335 /*
1293 /* 1336 * Are src and dst hardlinks of same inode? We can
1294 * Are src and dst hardlinks of same inode? We can 1337 * only tell with unix extensions enabled
1295 * only tell with unix extensions enabled 1338 */
1296 */ 1339 info_buf_source =
1297 info_buf_source = 1340 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1298 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), 1341 GFP_KERNEL);
1299 GFP_KERNEL); 1342 if (info_buf_source == NULL) {
1300 if (info_buf_source == NULL) 1343 rc = -ENOMEM;
1301 goto unlink_target; 1344 goto cifs_rename_exit;
1302 1345 }
1303 info_buf_target = info_buf_source + 1;
1304 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
1305 info_buf_source,
1306 cifs_sb_source->local_nls,
1307 cifs_sb_source->mnt_cifs_flags &
1308 CIFS_MOUNT_MAP_SPECIAL_CHR);
1309 if (rc != 0)
1310 goto unlink_target;
1311
1312 rc = CIFSSMBUnixQPathInfo(xid, pTcon,
1313 toName, info_buf_target,
1314 cifs_sb_target->local_nls,
1315 /* remap based on source sb */
1316 cifs_sb_source->mnt_cifs_flags &
1317 CIFS_MOUNT_MAP_SPECIAL_CHR);
1318 1346
1319 if (rc == 0 && (info_buf_source->UniqueId == 1347 info_buf_target = info_buf_source + 1;
1320 info_buf_target->UniqueId)) 1348 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
1321 /* same file, POSIX says that this is a noop */ 1349 info_buf_source,
1322 goto cifs_rename_exit; 1350 cifs_sb_source->local_nls,
1323 } /* else ... BB we could add the same check for Windows by 1351 cifs_sb_source->mnt_cifs_flags &
1352 CIFS_MOUNT_MAP_SPECIAL_CHR);
1353 if (tmprc != 0)
1354 goto unlink_target;
1355
1356 tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
1357 toName, info_buf_target,
1358 cifs_sb_target->local_nls,
1359 /* remap based on source sb */
1360 cifs_sb_source->mnt_cifs_flags &
1361 CIFS_MOUNT_MAP_SPECIAL_CHR);
1362
1363 if (tmprc == 0 && (info_buf_source->UniqueId ==
1364 info_buf_target->UniqueId))
1365 /* same file, POSIX says that this is a noop */
1366 goto cifs_rename_exit;
1367 } /* else ... BB we could add the same check for Windows by
1324 checking the UniqueId via FILE_INTERNAL_INFO */ 1368 checking the UniqueId via FILE_INTERNAL_INFO */
1369
1325unlink_target: 1370unlink_target:
1326 /* 1371 if ((rc == -EACCES) || (rc == -EEXIST)) {
1327 * we either can not tell the files are hardlinked (as with 1372 tmprc = cifs_unlink(target_dir, target_dentry);
1328 * Windows servers) or files are not hardlinked. Delete the 1373 if (tmprc)
1329 * target manually before renaming to follow POSIX rather than 1374 goto cifs_rename_exit;
1330 * Windows semantics 1375
1331 */ 1376 rc = cifs_do_rename(xid, source_dentry, fromName,
1332 cifs_unlink(target_inode, target_direntry); 1377 target_dentry, toName);
1333 rc = cifs_do_rename(xid, source_direntry, fromName,
1334 target_direntry, toName);
1335 } 1378 }
1336 1379
1337cifs_rename_exit: 1380cifs_rename_exit: