diff options
author | Paulo Alcantara <pc@manguebit.com> | 2023-11-25 23:55:03 -0300 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2024-01-07 15:46:05 -0600 |
commit | 102466f303ffcd5cff207b3c122557f73f1041e6 (patch) | |
tree | 3f6c69b86dbb4343870b24ea3a289823622835ae /fs/smb/client/smb2inode.c | |
parent | 3322960ce222997b1663ffa69e691b2edfec4ac9 (diff) |
smb: client: allow creating special files via reparse points
Add support for creating special files (e.g. char/block devices,
sockets, fifos) via NFS reparse points on SMB2+, which are fully
supported by most SMB servers and documented in MS-FSCC.
smb2_get_reparse_inode() creates the file with a corresponding reparse
point buffer set in @iov through a single roundtrip to the server.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202311260746.HOJ039BV-lkp@intel.com/
Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/smb/client/smb2inode.c')
-rw-r--r-- | fs/smb/client/smb2inode.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 98fa4f02fbd3..d662bad3b703 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -347,6 +347,22 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, smb2_set_related(&rqst[num_rqst++]); trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path); break; + case SMB2_OP_SET_REPARSE: + rqst[num_rqst].rq_iov = vars->io_iov; + rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov); + + rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst], + COMPOUND_FID, COMPOUND_FID, + FSCTL_SET_REPARSE_POINT, + in_iov[i].iov_base, + in_iov[i].iov_len, 0); + if (rc) + goto finished; + smb2_set_next_command(tcon, &rqst[num_rqst]); + smb2_set_related(&rqst[num_rqst++]); + trace_smb3_set_reparse_compound_enter(xid, ses->Suid, + tcon->tid, full_path); + break; default: cifs_dbg(VFS, "Invalid command\n"); rc = -EINVAL; @@ -503,6 +519,16 @@ finished: tcon->tid); SMB2_set_info_free(&rqst[num_rqst++]); break; + case SMB2_OP_SET_REPARSE: + if (rc) { + trace_smb3_set_reparse_compound_err(xid, ses->Suid, + tcon->tid, rc); + } else { + trace_smb3_set_reparse_compound_done(xid, ses->Suid, + tcon->tid); + } + SMB2_ioctl_free(&rqst[num_rqst++]); + break; } } SMB2_close_free(&rqst[num_rqst]); @@ -887,3 +913,52 @@ smb2_set_file_info(struct inode *inode, const char *full_path, cifs_put_tlink(tlink); return rc; } + +struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, + struct super_block *sb, + const unsigned int xid, + struct cifs_tcon *tcon, + const char *full_path, + struct kvec *iov) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsFileInfo *cfile; + struct inode *new = NULL; + struct kvec in_iov[2]; + int cmds[2]; + int da, co, cd; + int rc; + + da = SYNCHRONIZE | DELETE | + FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES; + co = CREATE_NOT_DIR | OPEN_REPARSE_POINT; + cd = FILE_CREATE; + cmds[0] = SMB2_OP_SET_REPARSE; + in_iov[0] = *iov; + in_iov[1].iov_base = data; + in_iov[1].iov_len = sizeof(*data); + + if (tcon->posix_extensions) { + cmds[1] = SMB2_OP_POSIX_QUERY_INFO; + cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, + da, cd, co, ACL_NO_MODE, in_iov, + cmds, 2, cfile, NULL, NULL, NULL, NULL); + if (!rc) { + rc = smb311_posix_get_inode_info(&new, full_path, + data, sb, xid); + } + } else { + cmds[1] = SMB2_OP_QUERY_INFO; + cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, + da, cd, co, ACL_NO_MODE, in_iov, + cmds, 2, cfile, NULL, NULL, NULL, NULL); + if (!rc) { + rc = cifs_get_inode_info(&new, full_path, + data, sb, xid, NULL); + } + } + return rc ? ERR_PTR(rc) : new; +} |