* [PATCH] smb: client: instantiate when creating SFU files
@ 2024-04-09 14:28 Paulo Alcantara
2024-04-09 16:51 ` Steve French
0 siblings, 1 reply; 2+ messages in thread
From: Paulo Alcantara @ 2024-04-09 14:28 UTC (permalink / raw)
To: smfrench; +Cc: linux-cifs, roberto.sassu, viro, torvalds, Paulo Alcantara
In cifs_sfu_make_node(), on success, instantiate rather than leave it
with dentry unhashed negative to support callers that expect mknod(2)
to always instantiate.
Fixes: 72bc63f5e23a ("smb3: fix creating FIFOs when mounting with "sfu" mount option")
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
---
fs/smb/client/smb2ops.c | 94 ++++++++++++++++++++++++-----------------
1 file changed, 55 insertions(+), 39 deletions(-)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index b156eefa75d7..78c94d0350fe 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4964,68 +4964,84 @@ static int smb2_next_header(struct TCP_Server_Info *server, char *buf,
return 0;
}
-int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
- struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+static int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev)
{
- struct cifs_open_info_data buf = {};
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms = {};
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_fid fid;
unsigned int bytes_written;
- struct win_dev *pdev;
+ struct win_dev pdev = {};
struct kvec iov[2];
__u32 oplock = server->oplocks ? REQ_OPLOCK : 0;
int rc;
- if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode))
+ switch (mode & S_IFMT) {
+ case S_IFCHR:
+ strscpy(pdev.type, "IntxCHR");
+ pdev.major = cpu_to_le64(MAJOR(dev));
+ pdev.minor = cpu_to_le64(MINOR(dev));
+ break;
+ case S_IFBLK:
+ strscpy(pdev.type, "IntxBLK");
+ pdev.major = cpu_to_le64(MAJOR(dev));
+ pdev.minor = cpu_to_le64(MINOR(dev));
+ break;
+ case S_IFIFO:
+ strscpy(pdev.type, "LnxFIFO");
+ break;
+ default:
return -EPERM;
+ }
- oparms = (struct cifs_open_parms) {
- .tcon = tcon,
- .cifs_sb = cifs_sb,
- .desired_access = GENERIC_WRITE,
- .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
- CREATE_OPTION_SPECIAL),
- .disposition = FILE_CREATE,
- .path = full_path,
- .fid = &fid,
- };
+ oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, GENERIC_WRITE,
+ FILE_CREATE, CREATE_NOT_DIR |
+ CREATE_OPTION_SPECIAL, ACL_NO_MODE);
+ oparms.fid = &fid;
- rc = server->ops->open(xid, &oparms, &oplock, &buf);
+ rc = server->ops->open(xid, &oparms, &oplock, NULL);
if (rc)
return rc;
- /*
- * BB Do not bother to decode buf since no local inode yet to put
- * timestamps in, but we can reuse it safely.
- */
- pdev = (struct win_dev *)&buf.fi;
io_parms.pid = current->tgid;
io_parms.tcon = tcon;
- io_parms.length = sizeof(*pdev);
- iov[1].iov_base = pdev;
- iov[1].iov_len = sizeof(*pdev);
- if (S_ISCHR(mode)) {
- memcpy(pdev->type, "IntxCHR", 8);
- pdev->major = cpu_to_le64(MAJOR(dev));
- pdev->minor = cpu_to_le64(MINOR(dev));
- } else if (S_ISBLK(mode)) {
- memcpy(pdev->type, "IntxBLK", 8);
- pdev->major = cpu_to_le64(MAJOR(dev));
- pdev->minor = cpu_to_le64(MINOR(dev));
- } else if (S_ISFIFO(mode)) {
- memcpy(pdev->type, "LnxFIFO", 8);
- }
+ io_parms.length = sizeof(pdev);
+ iov[1].iov_base = &pdev;
+ iov[1].iov_len = sizeof(pdev);
rc = server->ops->sync_write(xid, &fid, &io_parms,
&bytes_written, iov, 1);
server->ops->close(xid, tcon, &fid);
- d_drop(dentry);
- /* FIXME: add code here to set EAs */
- cifs_free_open_info(&buf);
+ return rc;
+}
+
+int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev)
+{
+ struct inode *new = NULL;
+ int rc;
+
+ rc = __cifs_sfu_make_node(xid, inode, dentry, tcon,
+ full_path, mode, dev);
+ if (rc)
+ return rc;
+
+ if (tcon->posix_extensions) {
+ rc = smb311_posix_get_inode_info(&new, full_path, NULL,
+ inode->i_sb, xid);
+ } else if (tcon->unix_ext) {
+ rc = cifs_get_inode_info_unix(&new, full_path,
+ inode->i_sb, xid);
+ } else {
+ rc = cifs_get_inode_info(&new, full_path, NULL,
+ inode->i_sb, xid, NULL);
+ }
+ if (!rc)
+ d_instantiate(dentry, new);
return rc;
}
--
2.44.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] smb: client: instantiate when creating SFU files
2024-04-09 14:28 [PATCH] smb: client: instantiate when creating SFU files Paulo Alcantara
@ 2024-04-09 16:51 ` Steve French
0 siblings, 0 replies; 2+ messages in thread
From: Steve French @ 2024-04-09 16:51 UTC (permalink / raw)
To: Paulo Alcantara; +Cc: linux-cifs, roberto.sassu, viro, torvalds
updated commit description with details of the repro scenario and
added to cifs-2.6.git for-next
On Tue, Apr 9, 2024 at 9:29 AM Paulo Alcantara <pc@manguebit.com> wrote:
>
> In cifs_sfu_make_node(), on success, instantiate rather than leave it
> with dentry unhashed negative to support callers that expect mknod(2)
> to always instantiate.
>
> Fixes: 72bc63f5e23a ("smb3: fix creating FIFOs when mounting with "sfu" mount option")
> Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
> ---
> fs/smb/client/smb2ops.c | 94 ++++++++++++++++++++++++-----------------
> 1 file changed, 55 insertions(+), 39 deletions(-)
>
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index b156eefa75d7..78c94d0350fe 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -4964,68 +4964,84 @@ static int smb2_next_header(struct TCP_Server_Info *server, char *buf,
> return 0;
> }
>
> -int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
> - struct dentry *dentry, struct cifs_tcon *tcon,
> - const char *full_path, umode_t mode, dev_t dev)
> +static int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path, umode_t mode, dev_t dev)
> {
> - struct cifs_open_info_data buf = {};
> struct TCP_Server_Info *server = tcon->ses->server;
> struct cifs_open_parms oparms;
> struct cifs_io_parms io_parms = {};
> struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
> struct cifs_fid fid;
> unsigned int bytes_written;
> - struct win_dev *pdev;
> + struct win_dev pdev = {};
> struct kvec iov[2];
> __u32 oplock = server->oplocks ? REQ_OPLOCK : 0;
> int rc;
>
> - if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode))
> + switch (mode & S_IFMT) {
> + case S_IFCHR:
> + strscpy(pdev.type, "IntxCHR");
> + pdev.major = cpu_to_le64(MAJOR(dev));
> + pdev.minor = cpu_to_le64(MINOR(dev));
> + break;
> + case S_IFBLK:
> + strscpy(pdev.type, "IntxBLK");
> + pdev.major = cpu_to_le64(MAJOR(dev));
> + pdev.minor = cpu_to_le64(MINOR(dev));
> + break;
> + case S_IFIFO:
> + strscpy(pdev.type, "LnxFIFO");
> + break;
> + default:
> return -EPERM;
> + }
>
> - oparms = (struct cifs_open_parms) {
> - .tcon = tcon,
> - .cifs_sb = cifs_sb,
> - .desired_access = GENERIC_WRITE,
> - .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
> - CREATE_OPTION_SPECIAL),
> - .disposition = FILE_CREATE,
> - .path = full_path,
> - .fid = &fid,
> - };
> + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, GENERIC_WRITE,
> + FILE_CREATE, CREATE_NOT_DIR |
> + CREATE_OPTION_SPECIAL, ACL_NO_MODE);
> + oparms.fid = &fid;
>
> - rc = server->ops->open(xid, &oparms, &oplock, &buf);
> + rc = server->ops->open(xid, &oparms, &oplock, NULL);
> if (rc)
> return rc;
>
> - /*
> - * BB Do not bother to decode buf since no local inode yet to put
> - * timestamps in, but we can reuse it safely.
> - */
> - pdev = (struct win_dev *)&buf.fi;
> io_parms.pid = current->tgid;
> io_parms.tcon = tcon;
> - io_parms.length = sizeof(*pdev);
> - iov[1].iov_base = pdev;
> - iov[1].iov_len = sizeof(*pdev);
> - if (S_ISCHR(mode)) {
> - memcpy(pdev->type, "IntxCHR", 8);
> - pdev->major = cpu_to_le64(MAJOR(dev));
> - pdev->minor = cpu_to_le64(MINOR(dev));
> - } else if (S_ISBLK(mode)) {
> - memcpy(pdev->type, "IntxBLK", 8);
> - pdev->major = cpu_to_le64(MAJOR(dev));
> - pdev->minor = cpu_to_le64(MINOR(dev));
> - } else if (S_ISFIFO(mode)) {
> - memcpy(pdev->type, "LnxFIFO", 8);
> - }
> + io_parms.length = sizeof(pdev);
> + iov[1].iov_base = &pdev;
> + iov[1].iov_len = sizeof(pdev);
>
> rc = server->ops->sync_write(xid, &fid, &io_parms,
> &bytes_written, iov, 1);
> server->ops->close(xid, tcon, &fid);
> - d_drop(dentry);
> - /* FIXME: add code here to set EAs */
> - cifs_free_open_info(&buf);
> + return rc;
> +}
> +
> +int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path, umode_t mode, dev_t dev)
> +{
> + struct inode *new = NULL;
> + int rc;
> +
> + rc = __cifs_sfu_make_node(xid, inode, dentry, tcon,
> + full_path, mode, dev);
> + if (rc)
> + return rc;
> +
> + if (tcon->posix_extensions) {
> + rc = smb311_posix_get_inode_info(&new, full_path, NULL,
> + inode->i_sb, xid);
> + } else if (tcon->unix_ext) {
> + rc = cifs_get_inode_info_unix(&new, full_path,
> + inode->i_sb, xid);
> + } else {
> + rc = cifs_get_inode_info(&new, full_path, NULL,
> + inode->i_sb, xid, NULL);
> + }
> + if (!rc)
> + d_instantiate(dentry, new);
> return rc;
> }
>
> --
> 2.44.0
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-04-09 16:52 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-09 14:28 [PATCH] smb: client: instantiate when creating SFU files Paulo Alcantara
2024-04-09 16:51 ` Steve French
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox