Commit 5408990a authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

smb: client: fix hardlinking of reparse points

The client was sending an SMB2_CREATE request without setting
OPEN_REPARSE_POINT flag thus failing the entire hardlink 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: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 7435d51b
...@@ -405,9 +405,11 @@ struct smb_version_operations { ...@@ -405,9 +405,11 @@ struct smb_version_operations {
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
/* send create hardlink request */ /* send create hardlink request */
int (*create_hardlink)(const unsigned int, struct cifs_tcon *, int (*create_hardlink)(const unsigned int xid,
const char *, const char *, struct cifs_tcon *tcon,
struct cifs_sb_info *); struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
/* query symlink target */ /* query symlink target */
int (*query_symlink)(const unsigned int xid, int (*query_symlink)(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
......
...@@ -447,9 +447,11 @@ extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -447,9 +447,11 @@ extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
int netfid, const char *target_name, int netfid, const char *target_name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, int CIFSCreateHardLink(const unsigned int xid,
const char *from_name, const char *to_name, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb); struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
extern int CIFSUnixCreateHardLink(const unsigned int xid, extern int CIFSUnixCreateHardLink(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *fromName, const char *toName, const char *fromName, const char *toName,
......
...@@ -2530,10 +2530,11 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2530,10 +2530,11 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
int int CIFSCreateHardLink(const unsigned int xid,
CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, struct dentry *source_dentry,
struct cifs_sb_info *cifs_sb) const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{ {
int rc = 0; int rc = 0;
NT_RENAME_REQ *pSMB = NULL; NT_RENAME_REQ *pSMB = NULL;
......
...@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
rc = -ENOSYS; rc = -ENOSYS;
goto cifs_hl_exit; goto cifs_hl_exit;
} }
rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, rc = server->ops->create_hardlink(xid, tcon, old_file,
cifs_sb); from_name, to_name, cifs_sb);
if ((rc == -EIO) || (rc == -EINVAL)) if ((rc == -EIO) || (rc == -EINVAL))
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
......
...@@ -44,6 +44,18 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov) ...@@ -44,6 +44,18 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
return buf; return buf;
} }
static inline __u32 file_create_options(struct dentry *dentry)
{
struct cifsInodeInfo *ci;
if (dentry) {
ci = CIFS_I(d_inode(dentry));
if (ci->cifsAttrs & ATTR_REPARSE)
return OPEN_REPARSE_POINT;
}
return 0;
}
/* /*
* note: If cfile is passed, the reference to it is dropped here. * note: If cfile is passed, the reference to it is dropped here.
* So make sure that you do not reuse cfile after return from this func. * So make sure that you do not reuse cfile after return from this func.
...@@ -920,15 +932,9 @@ int smb2_rename_path(const unsigned int xid, ...@@ -920,15 +932,9 @@ int smb2_rename_path(const unsigned int xid,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb) struct cifs_sb_info *cifs_sb)
{ {
struct cifsInodeInfo *ci;
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
__u32 co = 0; __u32 co = file_create_options(source_dentry);
if (source_dentry) {
ci = CIFS_I(d_inode(source_dentry));
if (ci->cifsAttrs & ATTR_REPARSE)
co |= OPEN_REPARSE_POINT;
}
drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb); drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile); cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
...@@ -936,13 +942,16 @@ int smb2_rename_path(const unsigned int xid, ...@@ -936,13 +942,16 @@ int smb2_rename_path(const unsigned int xid,
co, DELETE, SMB2_OP_RENAME, cfile); co, DELETE, SMB2_OP_RENAME, cfile);
} }
int int smb2_create_hardlink(const unsigned int xid,
smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, struct dentry *source_dentry,
struct cifs_sb_info *cifs_sb) const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb)
{ {
__u32 co = file_create_options(source_dentry);
return smb2_set_path_attr(xid, tcon, from_name, to_name, return smb2_set_path_attr(xid, tcon, from_name, to_name,
cifs_sb, 0, FILE_READ_ATTRIBUTES, cifs_sb, co, FILE_READ_ATTRIBUTES,
SMB2_OP_HARDLINK, NULL); SMB2_OP_HARDLINK, NULL);
} }
......
...@@ -91,9 +91,11 @@ int smb2_rename_path(const unsigned int xid, ...@@ -91,9 +91,11 @@ int smb2_rename_path(const unsigned int xid,
struct dentry *source_dentry, struct dentry *source_dentry,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, int smb2_create_hardlink(const unsigned int xid,
const char *from_name, const char *to_name, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb); struct dentry *source_dentry,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const unsigned char *path, struct cifs_sb_info *cifs_sb, const unsigned char *path,
char *pbuf, unsigned int *pbytes_written); char *pbuf, unsigned int *pbytes_written);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment