[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:
parent
9a8165fce7
commit
3270958b71
|
@ -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
|
Version 1.54
|
||||||
------------
|
------------
|
||||||
Fix premature write failure on congested networks (we would give up
|
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
|
authentication (requires setting SecurityFlags to 0x30030 to enable
|
||||||
lanman and plain text though). Fix writes to be at correct offset when
|
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.
|
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
|
Version 1.53
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -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;
|
extern const struct export_operations cifs_export_ops;
|
||||||
#endif /* EXPERIMENTAL */
|
#endif /* EXPERIMENTAL */
|
||||||
|
|
||||||
#define CIFS_VERSION "1.54"
|
#define CIFS_VERSION "1.55"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
|
102
fs/cifs/inode.c
102
fs/cifs/inode.c
|
@ -773,16 +773,17 @@ out:
|
||||||
* anything else.
|
* anything else.
|
||||||
*/
|
*/
|
||||||
static int
|
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 oplock = 0;
|
||||||
int rc;
|
int rc;
|
||||||
__u16 netfid;
|
__u16 netfid;
|
||||||
|
struct inode *inode = dentry->d_inode;
|
||||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
struct cifsTconInfo *tcon = cifs_sb->tcon;
|
struct cifsTconInfo *tcon = cifs_sb->tcon;
|
||||||
__u32 dosattr;
|
__u32 dosattr, origattr;
|
||||||
FILE_BASIC_INFO *info_buf;
|
FILE_BASIC_INFO *info_buf = NULL;
|
||||||
|
|
||||||
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
||||||
DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
|
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)
|
if (rc != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* set ATTR_HIDDEN and clear ATTR_READONLY */
|
origattr = cifsInode->cifsAttrs;
|
||||||
cifsInode = CIFS_I(inode);
|
if (origattr == 0)
|
||||||
dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
|
origattr |= ATTR_NORMAL;
|
||||||
|
|
||||||
|
dosattr = origattr & ~ATTR_READONLY;
|
||||||
if (dosattr == 0)
|
if (dosattr == 0)
|
||||||
dosattr |= ATTR_NORMAL;
|
dosattr |= ATTR_NORMAL;
|
||||||
dosattr |= ATTR_HIDDEN;
|
dosattr |= ATTR_HIDDEN;
|
||||||
|
|
||||||
info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
|
/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
|
||||||
if (info_buf == NULL) {
|
if (dosattr != origattr) {
|
||||||
rc = -ENOMEM;
|
info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
|
||||||
goto out_close;
|
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 */
|
/* rename the file */
|
||||||
rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
|
rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags &
|
cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
goto out;
|
rc = -ETXTBSY;
|
||||||
|
goto undo_setattr;
|
||||||
|
}
|
||||||
|
|
||||||
/* set DELETE_ON_CLOSE */
|
/* try to set DELETE_ON_CLOSE */
|
||||||
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
|
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.
|
* some samba versions return -ENOENT when we try to set the
|
||||||
* This means that some cifsXXX files may hang around after they
|
* file disposition here. Likely a samba bug, but work around
|
||||||
* shouldn't.
|
* 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
|
*
|
||||||
*/
|
* BB: remove this hack after more servers have the fix
|
||||||
if (rc == -ENOENT)
|
*/
|
||||||
rc = 0;
|
if (rc == -ENOENT)
|
||||||
|
rc = 0;
|
||||||
|
else if (rc != 0) {
|
||||||
|
rc = -ETXTBSY;
|
||||||
|
goto undo_rename;
|
||||||
|
}
|
||||||
|
cifsInode->delete_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
out_close:
|
out_close:
|
||||||
CIFSSMBClose(xid, tcon, netfid);
|
CIFSSMBClose(xid, tcon, netfid);
|
||||||
out:
|
out:
|
||||||
|
kfree(info_buf);
|
||||||
return rc;
|
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)
|
int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
|
@ -884,7 +922,7 @@ psx_del_no_retry:
|
||||||
} else if (rc == -ENOENT) {
|
} else if (rc == -ENOENT) {
|
||||||
d_drop(dentry);
|
d_drop(dentry);
|
||||||
} else if (rc == -ETXTBSY) {
|
} 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)
|
if (rc == 0)
|
||||||
drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
} else if (rc == -EACCES && dosattr == 0) {
|
} else if (rc == -EACCES && dosattr == 0) {
|
||||||
|
|
Loading…
Reference in New Issue