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

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
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -405,9 +405,11 @@ struct smb_version_operations {
		      const char *from_name, const char *to_name,
		      struct cifs_sb_info *cifs_sb);
	/* send create hardlink request */
	int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
			       const char *, const char *,
			       struct cifs_sb_info *);
	int (*create_hardlink)(const unsigned int xid,
			       struct cifs_tcon *tcon,
			       struct dentry *source_dentry,
			       const char *from_name, const char *to_name,
			       struct cifs_sb_info *cifs_sb);
	/* query symlink target */
	int (*query_symlink)(const unsigned int xid,
			     struct cifs_tcon *tcon,
+5 −3
Original line number Diff line number Diff line
@@ -447,7 +447,9 @@ extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
				 int netfid, const char *target_name,
				 const struct nls_table *nls_codepage,
				 int remap_special_chars);
extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
int CIFSCreateHardLink(const unsigned int xid,
		       struct cifs_tcon *tcon,
		       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,
+5 −4
Original line number Diff line number Diff line
@@ -2530,8 +2530,9 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
	return rc;
}

int
CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
int CIFSCreateHardLink(const unsigned int xid,
		       struct cifs_tcon *tcon,
		       struct dentry *source_dentry,
		       const char *from_name, const char *to_name,
		       struct cifs_sb_info *cifs_sb)
{
+2 −2
Original line number Diff line number Diff line
@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
			rc = -ENOSYS;
			goto cifs_hl_exit;
		}
		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
						  cifs_sb);
		rc = server->ops->create_hardlink(xid, tcon, old_file,
						  from_name, to_name, cifs_sb);
		if ((rc == -EIO) || (rc == -EINVAL))
			rc = -EOPNOTSUPP;
	}
+21 −12
Original line number Diff line number Diff line
@@ -44,6 +44,18 @@ static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
	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.
 * 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,
		     const char *from_name, const char *to_name,
		     struct cifs_sb_info *cifs_sb)
{
	struct cifsInodeInfo *ci;
	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);
	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);

@@ -936,13 +942,16 @@ int smb2_rename_path(const unsigned int xid,
				  co, DELETE, SMB2_OP_RENAME, cfile);
}

int
smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
int smb2_create_hardlink(const unsigned int xid,
			 struct cifs_tcon *tcon,
			 struct dentry *source_dentry,
			 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,
				  cifs_sb, 0, FILE_READ_ATTRIBUTES,
				  cifs_sb, co, FILE_READ_ATTRIBUTES,
				  SMB2_OP_HARDLINK, NULL);
}

Loading