aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-10-07 14:42:52 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-07 14:42:52 -0400
commit6050247d8089037d6d8ea0f3c62fe4a931c1ab14 (patch)
tree0be9729efe33be16bb12ccb289ec5992c450fcd9 /fs
parent6b37faa175311128dc920aaa57a5f7fab85537d7 (diff)
[CIFS] clean up error handling in cifs_unlink
Currently, if a standard delete fails and we end up getting -EACCES we try to clear ATTR_READONLY and try the delete again. If that then fails with -ETXTBSY then we try a rename_pending_delete. We aren't handling other errors appropriately though. Another client could have deleted the file in the meantime and we get back -ENOENT, for instance. In that case we wouldn't do a d_drop. Instead of retrying in a separate call, simply goto the original call and use the error handling from that. Also, we weren't properly undoing any attribute changes that were done before returning an error back to the caller. CC: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/inode.c39
1 files changed, 19 insertions, 20 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e387ed3f9446..a8c833345fc9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -837,12 +837,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
837 int xid; 837 int xid;
838 char *full_path = NULL; 838 char *full_path = NULL;
839 struct inode *inode = dentry->d_inode; 839 struct inode *inode = dentry->d_inode;
840 struct cifsInodeInfo *cifsInode; 840 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
841 struct super_block *sb = dir->i_sb; 841 struct super_block *sb = dir->i_sb;
842 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 842 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
843 struct cifsTconInfo *tcon = cifs_sb->tcon; 843 struct cifsTconInfo *tcon = cifs_sb->tcon;
844 struct iattr *attrs; 844 struct iattr *attrs = NULL;
845 __u32 dosattr; 845 __u32 dosattr = 0, origattr = 0;
846 846
847 cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry)); 847 cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
848 848
@@ -867,8 +867,10 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
867 goto psx_del_no_retry; 867 goto psx_del_no_retry;
868 } 868 }
869 869
870retry_std_delete:
870 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls, 871 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
871 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 872 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
873
872psx_del_no_retry: 874psx_del_no_retry:
873 if (!rc) { 875 if (!rc) {
874 if (inode) 876 if (inode)
@@ -879,8 +881,7 @@ psx_del_no_retry:
879 rc = cifs_rename_pending_delete(full_path, inode, xid); 881 rc = cifs_rename_pending_delete(full_path, inode, xid);
880 if (rc == 0) 882 if (rc == 0)
881 drop_nlink(inode); 883 drop_nlink(inode);
882 } else if (rc == -EACCES) { 884 } else if (rc == -EACCES && dosattr == 0) {
883 /* try only if r/o attribute set in local lookup data? */
884 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); 885 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
885 if (attrs == NULL) { 886 if (attrs == NULL) {
886 rc = -ENOMEM; 887 rc = -ENOMEM;
@@ -888,28 +889,25 @@ psx_del_no_retry:
888 } 889 }
889 890
890 /* try to reset dos attributes */ 891 /* try to reset dos attributes */
891 cifsInode = CIFS_I(inode); 892 origattr = cifsInode->cifsAttrs;
892 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; 893 if (origattr == 0)
894 origattr |= ATTR_NORMAL;
895 dosattr = origattr & ~ATTR_READONLY;
893 if (dosattr == 0) 896 if (dosattr == 0)
894 dosattr |= ATTR_NORMAL; 897 dosattr |= ATTR_NORMAL;
895 dosattr |= ATTR_HIDDEN; 898 dosattr |= ATTR_HIDDEN;
896 899
897 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 900 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
898 kfree(attrs);
899 if (rc != 0) 901 if (rc != 0)
900 goto out_reval; 902 goto out_reval;
901 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls, 903
902 cifs_sb->mnt_cifs_flags & 904 goto retry_std_delete;
903 CIFS_MOUNT_MAP_SPECIAL_CHR);
904 if (rc == 0) {
905 if (inode)
906 drop_nlink(inode);
907 } else if (rc == -ETXTBSY) {
908 rc = cifs_rename_pending_delete(full_path, inode, xid);
909 if (rc == 0)
910 drop_nlink(inode);
911 }
912 } 905 }
906
907 /* undo the setattr if we errored out and it's needed */
908 if (rc != 0 && dosattr != 0)
909 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
910
913out_reval: 911out_reval:
914 if (inode) { 912 if (inode) {
915 cifsInode = CIFS_I(inode); 913 cifsInode = CIFS_I(inode);
@@ -919,9 +917,10 @@ out_reval:
919 } 917 }
920 dir->i_ctime = dir->i_mtime = current_fs_time(sb); 918 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
921 cifsInode = CIFS_I(dir); 919 cifsInode = CIFS_I(dir);
922 cifsInode->time = 0; /* force revalidate of dir as well */ 920 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
923 921
924 kfree(full_path); 922 kfree(full_path);
923 kfree(attrs);
925 FreeXid(xid); 924 FreeXid(xid);
926 return rc; 925 return rc;
927} 926}