[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>
This commit is contained in:
Steve French 2008-10-20 00:44:19 +00:00
parent 9a8165fce7
commit 3270958b71
3 changed files with 79 additions and 33 deletions

View File

@ -1,3 +1,10 @@
Version 1.55
------------
Various fixes to make delete of open files behavior more predictable
(when delete of an open file fails we mark the file as "delete-on-close"
in a way that more servers accept, but only if we can first rename the
file to a temporary name)
Version 1.54
------------
Fix premature write failure on congested networks (we would give up
@ -13,6 +20,7 @@ on dns_upcall (resolving DFS referralls). Fix plain text password
authentication (requires setting SecurityFlags to 0x30030 to enable
lanman and plain text though). Fix writes to be at correct offset when
file is open with O_APPEND and file is on a directio (forcediretio) mount.
Fix bug in rewinding readdir directory searches. Add nodfs mount option.
Version 1.53
------------

View File

@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
#define CIFS_VERSION "1.54"
#define CIFS_VERSION "1.55"
#endif /* _CIFSFS_H */

View File

@ -773,16 +773,17 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
* anything else.
*/
static int
cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
{
int oplock = 0;
int rc;
__u16 netfid;
struct inode *inode = dentry->d_inode;
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *tcon = cifs_sb->tcon;
__u32 dosattr;
FILE_BASIC_INFO *info_buf;
__u32 dosattr, origattr;
FILE_BASIC_INFO *info_buf = NULL;
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
@ -791,50 +792,87 @@ cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
if (rc != 0)
goto out;
/* set ATTR_HIDDEN and clear ATTR_READONLY */
cifsInode = CIFS_I(inode);
dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
origattr = cifsInode->cifsAttrs;
if (origattr == 0)
origattr |= ATTR_NORMAL;
dosattr = origattr & ~ATTR_READONLY;
if (dosattr == 0)
dosattr |= ATTR_NORMAL;
dosattr |= ATTR_HIDDEN;
info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
if (info_buf == NULL) {
rc = -ENOMEM;
goto out_close;
/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
if (dosattr != origattr) {
info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
if (info_buf == NULL) {
rc = -ENOMEM;
goto out_close;
}
info_buf->Attributes = cpu_to_le32(dosattr);
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
current->tgid);
/* although we would like to mark the file hidden
if that fails we will still try to rename it */
if (rc != 0) {
cifsInode->cifsAttrs = dosattr;
else
dosattr = origattr; /* since not able to change them */
}
info_buf->Attributes = cpu_to_le32(dosattr);
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
kfree(info_buf);
if (rc != 0)
goto out_close;
cifsInode->cifsAttrs = dosattr;
/* rename the file */
rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0)
goto out;
if (rc != 0) {
rc = -ETXTBSY;
goto undo_setattr;
}
/* set DELETE_ON_CLOSE */
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
/*
* some samba versions return -ENOENT when we try to set the file
* disposition here. Likely a samba bug, but work around it for now.
* This means that some cifsXXX files may hang around after they
* shouldn't.
*
* BB: remove this once fixed samba servers are in the field
*/
if (rc == -ENOENT)
rc = 0;
/* try to set DELETE_ON_CLOSE */
if (!cifsInode->delete_pending) {
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
current->tgid);
/*
* some samba versions return -ENOENT when we try to set the
* file disposition here. Likely a samba bug, but work around
* it for now. This means that some cifsXXX files may hang
* around after they shouldn't.
*
* BB: remove this hack after more servers have the fix
*/
if (rc == -ENOENT)
rc = 0;
else if (rc != 0) {
rc = -ETXTBSY;
goto undo_rename;
}
cifsInode->delete_pending = true;
}
out_close:
CIFSSMBClose(xid, tcon, netfid);
out:
kfree(info_buf);
return rc;
/*
* reset everything back to the original state. Don't bother
* dealing with errors here since we can't do anything about
* them anyway.
*/
undo_rename:
CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
undo_setattr:
if (dosattr != origattr) {
info_buf->Attributes = cpu_to_le32(origattr);
if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
current->tgid))
cifsInode->cifsAttrs = origattr;
}
goto out_close;
}
int cifs_unlink(struct inode *dir, struct dentry *dentry)
@ -884,7 +922,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
} else if (rc == -ENOENT) {
d_drop(dentry);
} else if (rc == -ETXTBSY) {
rc = cifs_rename_pending_delete(full_path, inode, xid);
rc = cifs_rename_pending_delete(full_path, dentry, xid);
if (rc == 0)
drop_nlink(inode);
} else if (rc == -EACCES && dosattr == 0) {