diff options
author | Steve French <sfrench@us.ibm.com> | 2008-10-19 20:44:19 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-10-19 20:44:19 -0400 |
commit | 3270958b717a13d0228803254609c19184854b9b (patch) | |
tree | 50d1affc68add3e89798f647bb6abc7532f62e51 /fs/cifs/inode.c | |
parent | 9a8165fce724d1aba21e2c713ac6ba11dbfecafa (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>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 102 |
1 files changed, 70 insertions, 32 deletions
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 | */ |
775 | static int | 775 | static int |
776 | cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid) | 776 | cifs_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 | ||
834 | out_close: | 852 | out_close: |
835 | CIFSSMBClose(xid, tcon, netfid); | 853 | CIFSSMBClose(xid, tcon, netfid); |
836 | out: | 854 | out: |
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 | */ | ||
863 | undo_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); | ||
867 | undo_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 | ||
840 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 878 | int 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) { |