smb: client: fix hardlinking of reparse points
authorSteve French <stfrench@microsoft.com>
Sun, 28 Jan 2024 18:15:39 +0000 (12:15 -0600)
committerSteve French <stfrench@microsoft.com>
Sun, 28 Jan 2024 18:15:39 +0000 (12:15 -0600)
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: Paulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/link.c
fs/cifs/smb2inode.c
fs/cifs/smb2proto.h

index 9dc305278c6dc9fda251c0ea3d5c9f63e81a50e8..579fa77e77edd5c54e0b0c31e47b2f5629bb0edb 100644 (file)
@@ -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,
index c1d9ba2a07d09936fb0ec244430fae466a5166a2..500301b48703f909bb9382f6a52bbbc38af5782a 100644 (file)
@@ -443,9 +443,11 @@ 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,
-                             const char *from_name, const char *to_name,
-                             struct cifs_sb_info *cifs_sb);
+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,
                        struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
index b57f3726a6f901623826c0de1e531b513974e12c..3678df0835a61c6ba1ed345bc34b5bb01d98227d 100644 (file)
@@ -2534,10 +2534,11 @@ createHardLinkRetry:
        return rc;
 }
 
-int
-CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
-                  const char *from_name, const char *to_name,
-                  struct cifs_sb_info *cifs_sb)
+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)
 {
        int rc = 0;
        NT_RENAME_REQ *pSMB = NULL;
index ffb6ec9c1d4506df8f94154a10c79f7264d06132..f11b2b686de78879b10ecbb37816033bf0e11b0a 100644 (file)
@@ -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;
        }
index 2d9cdc1944031ca4e73a03915edeb7107026b0f6..919f778be84d0ba69e39d135097a470987e6d0ae 100644 (file)
@@ -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,
-                    const char *from_name, const char *to_name,
-                    struct cifs_sb_info *cifs_sb)
+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);
 }
 
index aef50316670acdccb398a7812e7f07514de811de..efa2f8fe23449ad7fea349949a3ba3c77c93a9e1 100644 (file)
@@ -91,9 +91,11 @@ int smb2_rename_path(const unsigned int xid,
                     struct dentry *source_dentry,
                     const char *from_name, const char *to_name,
                     struct cifs_sb_info *cifs_sb);
-extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
-                               const char *from_name, const char *to_name,
-                               struct cifs_sb_info *cifs_sb);
+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);
 extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
                        struct cifs_sb_info *cifs_sb, const unsigned char *path,
                        char *pbuf, unsigned int *pbytes_written);