summaryrefslogtreecommitdiff
path: root/fs/smb
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb')
-rw-r--r--fs/smb/client/smb2inode.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index b992117377e9..4e9e225520a6 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -1205,9 +1205,12 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsFileInfo *cfile;
struct inode *new = NULL;
+ int out_buftype[4] = {};
+ struct kvec out_iov[4] = {};
struct kvec in_iov[2];
int cmds[2];
int rc;
+ int i;
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
SYNCHRONIZE | DELETE |
@@ -1228,7 +1231,7 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
- in_iov, cmds, 2, cfile, NULL, NULL, NULL);
+ in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) {
rc = smb311_posix_get_inode_info(&new, full_path,
data, sb, xid);
@@ -1237,12 +1240,29 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
cmds[1] = SMB2_OP_QUERY_INFO;
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
- in_iov, cmds, 2, cfile, NULL, NULL, NULL);
+ in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
if (!rc) {
rc = cifs_get_inode_info(&new, full_path,
data, sb, xid, NULL);
}
}
+
+
+ /*
+ * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
+ * remove the intermediate object created by CREATE. Otherwise
+ * empty object stay on the server when reparse call failed.
+ */
+ if (rc &&
+ out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
+ ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
+ (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
+ ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
+ smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
+
+ for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
+ free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
+
return rc ? ERR_PTR(rc) : new;
}