aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-10-19 20:44:19 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-19 20:44:19 -0400
commit3270958b717a13d0228803254609c19184854b9b (patch)
tree50d1affc68add3e89798f647bb6abc7532f62e51
parent9a8165fce724d1aba21e2c713ac6ba11dbfecafa (diff)
[CIFS] undo changes in cifs_rename_pending_delete if it errors out
The cifs_rename_pending_delete process involves multiple steps. If it fails and we're going to return error, we don't want to leave things in a half-finished state. Add code to the function to undo changes if a call fails. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/CHANGES8
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/inode.c102
3 files changed, 79 insertions, 33 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 06e521a945c3..a7255751ffbc 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,10 @@
1Version 1.55
2------------
3Various fixes to make delete of open files behavior more predictable
4(when delete of an open file fails we mark the file as "delete-on-close"
5in a way that more servers accept, but only if we can first rename the
6file to a temporary name)
7
1Version 1.54 8Version 1.54
2------------ 9------------
3Fix premature write failure on congested networks (we would give up 10Fix premature write failure on congested networks (we would give up
@@ -13,6 +20,7 @@ on dns_upcall (resolving DFS referralls). Fix plain text password
13authentication (requires setting SecurityFlags to 0x30030 to enable 20authentication (requires setting SecurityFlags to 0x30030 to enable
14lanman and plain text though). Fix writes to be at correct offset when 21lanman and plain text though). Fix writes to be at correct offset when
15file is open with O_APPEND and file is on a directio (forcediretio) mount. 22file is open with O_APPEND and file is on a directio (forcediretio) mount.
23Fix bug in rewinding readdir directory searches. Add nodfs mount option.
16 24
17Version 1.53 25Version 1.53
18------------ 26------------
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index f7b4a5cd837b..074de0b5064d 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
101extern const struct export_operations cifs_export_ops; 101extern const struct export_operations cifs_export_ops;
102#endif /* EXPERIMENTAL */ 102#endif /* EXPERIMENTAL */
103 103
104#define CIFS_VERSION "1.54" 104#define CIFS_VERSION "1.55"
105#endif /* _CIFSFS_H */ 105#endif /* _CIFSFS_H */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index dea9eeb58b00..232ab16d7fd4 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -773,16 +773,17 @@ out:
773 * anything else. 773 * anything else.
774 */ 774 */
775static int 775static int
776cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid) 776cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
777{ 777{
778 int oplock = 0; 778 int oplock = 0;
779 int rc; 779 int rc;
780 __u16 netfid; 780 __u16 netfid;
781 struct inode *inode = dentry->d_inode;
781 struct cifsInodeInfo *cifsInode = CIFS_I(inode); 782 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
782 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 783 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
783 struct cifsTconInfo *tcon = cifs_sb->tcon; 784 struct cifsTconInfo *tcon = cifs_sb->tcon;
784 __u32 dosattr; 785 __u32 dosattr, origattr;
785 FILE_BASIC_INFO *info_buf; 786 FILE_BASIC_INFO *info_buf = NULL;
786 787
787 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, 788 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
788 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, 789 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
@@ -791,50 +792,87 @@ cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
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 /* rename the file */ 822 /* rename the file */
814 rc = 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);
817 if (rc != 0) 826 if (rc != 0) {
818 goto out; 827 rc = -ETXTBSY;
819 828 goto undo_setattr;
820 /* set DELETE_ON_CLOSE */ 829 }
821 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
822 830
823 /* 831 /* try to set DELETE_ON_CLOSE */
824 * some samba versions return -ENOENT when we try to set the file 832 if (!cifsInode->delete_pending) {
825 * disposition here. Likely a samba bug, but work around it for now. 833 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
826 * This means that some cifsXXX files may hang around after they 834 current->tgid);
827 * shouldn't. 835 /*
828 * 836 * some samba versions return -ENOENT when we try to set the
829 * BB: remove this once fixed samba servers are in the field 837 * file disposition here. Likely a samba bug, but work around
830 */ 838 * it for now. This means that some cifsXXX files may hang
831 if (rc == -ENOENT) 839 * around after they shouldn't.
832 rc = 0; 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 }
833 851
834out_close: 852out_close:
835 CIFSSMBClose(xid, tcon, netfid); 853 CIFSSMBClose(xid, tcon, netfid);
836out: 854out:
855 kfree(info_buf);
837 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;
838} 876}
839 877
840int cifs_unlink(struct inode *dir, struct dentry *dentry) 878int cifs_unlink(struct inode *dir, struct dentry *dentry)
@@ -884,7 +922,7 @@ psx_del_no_retry:
884 } else if (rc == -ENOENT) { 922 } else if (rc == -ENOENT) {
885 d_drop(dentry); 923 d_drop(dentry);
886 } else if (rc == -ETXTBSY) { 924 } else if (rc == -ETXTBSY) {
887 rc = cifs_rename_pending_delete(full_path, inode, xid); 925 rc = cifs_rename_pending_delete(full_path, dentry, xid);
888 if (rc == 0) 926 if (rc == 0)
889 drop_nlink(inode); 927 drop_nlink(inode);
890 } else if (rc == -EACCES && dosattr == 0) { 928 } else if (rc == -EACCES && dosattr == 0) {