smb: client: fix hardlinking of reparse points
authorPaulo Alcantara <pc@manguebit.com>
Sun, 26 Nov 2023 02:55:07 +0000 (23:55 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Feb 2024 20:14:17 +0000 (20:14 +0000)
[ Upstream commit 5408990aa662bcfd6ba894734023a023a16e8729 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/cifsglob.h
fs/smb/client/cifsproto.h
fs/smb/client/cifssmb.c
fs/smb/client/link.c
fs/smb/client/smb2inode.c
fs/smb/client/smb2proto.h

index 4d07b96..942e6ec 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 f89e6c2..260a629 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 5bdea01..e9e33b0 100644 (file)
@@ -2530,10 +2530,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 c66be49..6c4ae52 100644 (file)
@@ -522,8 +522,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 c3e2867..6cac0b1 100644 (file)
@@ -35,6 +35,18 @@ free_set_inf_compound(struct smb_rqst *rqst)
                SMB2_close_free(&rqst[2]);
 }
 
+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.
@@ -809,15 +821,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);
 
@@ -825,13 +831,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 7cbf1a7..a8084ce 100644 (file)
@@ -85,9 +85,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);