Skip to content

Commit 7435d51

Browse files
Paulo Alcantarasmfrench
authored andcommitted
smb: client: fix renaming of reparse points
The client was sending an SMB2_CREATE request without setting OPEN_REPARSE_POINT flag thus failing the entire rename operation. Fix this by setting OPEN_REPARSE_POINT in create options for SMB2_CREATE request when the source inode is a repase point. Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 67ec994 commit 7435d51

6 files changed

Lines changed: 55 additions & 31 deletions

File tree

fs/smb/client/cifsglob.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,18 @@ struct cifs_open_info_data {
210210
};
211211
};
212212

213-
#define cifs_open_data_reparse(d) \
214-
((d)->reparse_point || \
215-
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
213+
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
214+
{
215+
struct smb2_file_all_info *fi = &data->fi;
216+
u32 attrs = le32_to_cpu(fi->Attributes);
217+
bool ret;
218+
219+
ret = data->reparse_point || (attrs & ATTR_REPARSE);
220+
if (ret)
221+
attrs |= ATTR_REPARSE;
222+
fi->Attributes = cpu_to_le32(attrs);
223+
return ret;
224+
}
216225

217226
/*
218227
*****************************************************************
@@ -390,8 +399,11 @@ struct smb_version_operations {
390399
int (*rename_pending_delete)(const char *, struct dentry *,
391400
const unsigned int);
392401
/* send rename request */
393-
int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
394-
const char *, struct cifs_sb_info *);
402+
int (*rename)(const unsigned int xid,
403+
struct cifs_tcon *tcon,
404+
struct dentry *source_dentry,
405+
const char *from_name, const char *to_name,
406+
struct cifs_sb_info *cifs_sb);
395407
/* send create hardlink request */
396408
int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
397409
const char *, const char *,

fs/smb/client/cifsproto.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,10 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
439439
int remap_special_chars);
440440
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
441441
const char *name, struct cifs_sb_info *cifs_sb);
442-
extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
443-
const char *from_name, const char *to_name,
444-
struct cifs_sb_info *cifs_sb);
442+
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
443+
struct dentry *source_dentry,
444+
const char *from_name, const char *to_name,
445+
struct cifs_sb_info *cifs_sb);
445446
extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
446447
int netfid, const char *target_name,
447448
const struct nls_table *nls_codepage,

fs/smb/client/cifssmb.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,10 +2149,10 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
21492149
return rc;
21502150
}
21512151

2152-
int
2153-
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2154-
const char *from_name, const char *to_name,
2155-
struct cifs_sb_info *cifs_sb)
2152+
int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2153+
struct dentry *source_dentry,
2154+
const char *from_name, const char *to_name,
2155+
struct cifs_sb_info *cifs_sb)
21562156
{
21572157
int rc = 0;
21582158
RENAME_REQ *pSMB = NULL;

fs/smb/client/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2244,7 +2244,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
22442244
return -ENOSYS;
22452245

22462246
/* try path-based rename first */
2247-
rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
2247+
rc = server->ops->rename(xid, tcon, from_dentry,
2248+
from_path, to_path, cifs_sb);
22482249

22492250
/*
22502251
* Don't bother with rename by filehandle unless file is busy and

fs/smb/client/smb2inode.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -889,11 +889,11 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
889889
NULL, NULL, NULL, NULL, NULL);
890890
}
891891

892-
static int
893-
smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
894-
const char *from_name, const char *to_name,
895-
struct cifs_sb_info *cifs_sb, __u32 access, int command,
896-
struct cifsFileInfo *cfile)
892+
static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
893+
const char *from_name, const char *to_name,
894+
struct cifs_sb_info *cifs_sb,
895+
__u32 create_options, __u32 access,
896+
int command, struct cifsFileInfo *cfile)
897897
{
898898
struct kvec in_iov;
899899
__le16 *smb2_to_name = NULL;
@@ -907,35 +907,43 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
907907
in_iov.iov_base = smb2_to_name;
908908
in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
909909
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
910-
FILE_OPEN, 0, ACL_NO_MODE, &in_iov,
910+
FILE_OPEN, create_options, ACL_NO_MODE, &in_iov,
911911
&command, 1, cfile, NULL, NULL, NULL, NULL);
912912
smb2_rename_path:
913913
kfree(smb2_to_name);
914914
return rc;
915915
}
916916

917-
int
918-
smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
919-
const char *from_name, const char *to_name,
920-
struct cifs_sb_info *cifs_sb)
917+
int smb2_rename_path(const unsigned int xid,
918+
struct cifs_tcon *tcon,
919+
struct dentry *source_dentry,
920+
const char *from_name, const char *to_name,
921+
struct cifs_sb_info *cifs_sb)
921922
{
923+
struct cifsInodeInfo *ci;
922924
struct cifsFileInfo *cfile;
925+
__u32 co = 0;
923926

927+
if (source_dentry) {
928+
ci = CIFS_I(d_inode(source_dentry));
929+
if (ci->cifsAttrs & ATTR_REPARSE)
930+
co |= OPEN_REPARSE_POINT;
931+
}
924932
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
925933
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
926934

927-
return smb2_set_path_attr(xid, tcon, from_name, to_name,
928-
cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
935+
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
936+
co, DELETE, SMB2_OP_RENAME, cfile);
929937
}
930938

931939
int
932940
smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
933941
const char *from_name, const char *to_name,
934942
struct cifs_sb_info *cifs_sb)
935943
{
936-
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
937-
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
938-
NULL);
944+
return smb2_set_path_attr(xid, tcon, from_name, to_name,
945+
cifs_sb, 0, FILE_READ_ATTRIBUTES,
946+
SMB2_OP_HARDLINK, NULL);
939947
}
940948

941949
int

fs/smb/client/smb2proto.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
8686
const char *name, struct cifs_sb_info *cifs_sb);
8787
extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
8888
const char *name, struct cifs_sb_info *cifs_sb);
89-
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
90-
const char *from_name, const char *to_name,
91-
struct cifs_sb_info *cifs_sb);
89+
int smb2_rename_path(const unsigned int xid,
90+
struct cifs_tcon *tcon,
91+
struct dentry *source_dentry,
92+
const char *from_name, const char *to_name,
93+
struct cifs_sb_info *cifs_sb);
9294
extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
9395
const char *from_name, const char *to_name,
9496
struct cifs_sb_info *cifs_sb);

0 commit comments

Comments
 (0)