Skip to content

Commit c847dcc

Browse files
aaptelSteve French
authored andcommitted
CIFS: make mknod() an smb_version_op
This cleanup removes cifs specific code from SMB2/SMB3 code paths which is cleaner and easier to maintain as the code to handle special files is improved. Below is an example creating special files using 'sfu' mount option over SMB3 to Windows (with this patch) (Note that to Samba server, support for saving dos attributes has to be enabled for the SFU mount option to work). In the future this will also make implementation of creating special files as reparse points easier (as Windows NFS server does for example). root@smf-Thinkpad-P51:~# stat -c "%F" /mnt2/char character special file root@smf-Thinkpad-P51:~# stat -c "%F" /mnt2/block block special file Signed-off-by: Aurelien Aptel <aaptel@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
1 parent 6552580 commit c847dcc

File tree

4 files changed

+239
-104
lines changed

4 files changed

+239
-104
lines changed

fs/cifs/cifsglob.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,14 @@ struct smb_version_operations {
479479
struct cifs_tcon *tcon,
480480
__le16 *path, int is_dir,
481481
unsigned long p);
482+
/* make unix special files (block, char, fifo, socket) */
483+
int (*make_node)(unsigned int xid,
484+
struct inode *inode,
485+
struct dentry *dentry,
486+
struct cifs_tcon *tcon,
487+
char *full_path,
488+
umode_t mode,
489+
dev_t device_number);
482490
};
483491

484492
struct smb_version_values {

fs/cifs/dir.c

Lines changed: 3 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -621,20 +621,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
621621
{
622622
int rc = -EPERM;
623623
unsigned int xid;
624-
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
625624
struct cifs_sb_info *cifs_sb;
626625
struct tcon_link *tlink;
627626
struct cifs_tcon *tcon;
628-
struct cifs_io_parms io_parms;
629627
char *full_path = NULL;
630-
struct inode *newinode = NULL;
631-
__u32 oplock = 0;
632-
struct cifs_fid fid;
633-
struct cifs_open_parms oparms;
634-
FILE_ALL_INFO *buf = NULL;
635-
unsigned int bytes_written;
636-
struct win_dev *pdev;
637-
struct kvec iov[2];
638628

639629
if (!old_valid_dev(device_number))
640630
return -EINVAL;
@@ -654,103 +644,12 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
654644
goto mknod_out;
655645
}
656646

657-
if (tcon->unix_ext) {
658-
struct cifs_unix_set_info_args args = {
659-
.mode = mode & ~current_umask(),
660-
.ctime = NO_CHANGE_64,
661-
.atime = NO_CHANGE_64,
662-
.mtime = NO_CHANGE_64,
663-
.device = device_number,
664-
};
665-
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
666-
args.uid = current_fsuid();
667-
args.gid = current_fsgid();
668-
} else {
669-
args.uid = INVALID_UID; /* no change */
670-
args.gid = INVALID_GID; /* no change */
671-
}
672-
rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
673-
cifs_sb->local_nls,
674-
cifs_remap(cifs_sb));
675-
if (rc)
676-
goto mknod_out;
677-
678-
rc = cifs_get_inode_info_unix(&newinode, full_path,
679-
inode->i_sb, xid);
680-
681-
if (rc == 0)
682-
d_instantiate(direntry, newinode);
683-
goto mknod_out;
684-
}
685-
686-
if (!S_ISCHR(mode) && !S_ISBLK(mode))
687-
goto mknod_out;
688-
689-
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
690-
goto mknod_out;
691-
692-
693-
cifs_dbg(FYI, "sfu compat create special file\n");
694-
695-
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
696-
if (buf == NULL) {
697-
rc = -ENOMEM;
698-
goto mknod_out;
699-
}
700-
701-
if (backup_cred(cifs_sb))
702-
create_options |= CREATE_OPEN_BACKUP_INTENT;
703-
704-
oparms.tcon = tcon;
705-
oparms.cifs_sb = cifs_sb;
706-
oparms.desired_access = GENERIC_WRITE;
707-
oparms.create_options = create_options;
708-
oparms.disposition = FILE_CREATE;
709-
oparms.path = full_path;
710-
oparms.fid = &fid;
711-
oparms.reconnect = false;
712-
713-
if (tcon->ses->server->oplocks)
714-
oplock = REQ_OPLOCK;
715-
else
716-
oplock = 0;
717-
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
718-
if (rc)
719-
goto mknod_out;
720-
721-
/*
722-
* BB Do not bother to decode buf since no local inode yet to put
723-
* timestamps in, but we can reuse it safely.
724-
*/
725-
726-
pdev = (struct win_dev *)buf;
727-
io_parms.pid = current->tgid;
728-
io_parms.tcon = tcon;
729-
io_parms.offset = 0;
730-
io_parms.length = sizeof(struct win_dev);
731-
iov[1].iov_base = buf;
732-
iov[1].iov_len = sizeof(struct win_dev);
733-
if (S_ISCHR(mode)) {
734-
memcpy(pdev->type, "IntxCHR", 8);
735-
pdev->major = cpu_to_le64(MAJOR(device_number));
736-
pdev->minor = cpu_to_le64(MINOR(device_number));
737-
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
738-
&bytes_written, iov, 1);
739-
} else if (S_ISBLK(mode)) {
740-
memcpy(pdev->type, "IntxBLK", 8);
741-
pdev->major = cpu_to_le64(MAJOR(device_number));
742-
pdev->minor = cpu_to_le64(MINOR(device_number));
743-
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
744-
&bytes_written, iov, 1);
745-
}
746-
tcon->ses->server->ops->close(xid, tcon, &fid);
747-
d_drop(direntry);
748-
749-
/* FIXME: add code here to set EAs */
647+
rc = tcon->ses->server->ops->make_node(xid, inode, direntry, tcon,
648+
full_path, mode,
649+
device_number);
750650

751651
mknod_out:
752652
kfree(full_path);
753-
kfree(buf);
754653
free_xid(xid);
755654
cifs_put_tlink(tlink);
756655
return rc;

fs/cifs/smb1ops.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,131 @@ cifs_can_echo(struct TCP_Server_Info *server)
10271027
return false;
10281028
}
10291029

1030+
static int
1031+
cifs_make_node(unsigned int xid, struct inode *inode,
1032+
struct dentry *dentry, struct cifs_tcon *tcon,
1033+
char *full_path, umode_t mode, dev_t dev)
1034+
{
1035+
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1036+
struct inode *newinode = NULL;
1037+
int rc = -EPERM;
1038+
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
1039+
FILE_ALL_INFO *buf = NULL;
1040+
struct cifs_io_parms io_parms;
1041+
__u32 oplock = 0;
1042+
struct cifs_fid fid;
1043+
struct cifs_open_parms oparms;
1044+
unsigned int bytes_written;
1045+
struct win_dev *pdev;
1046+
struct kvec iov[2];
1047+
1048+
if (tcon->unix_ext) {
1049+
/*
1050+
* SMB1 Unix Extensions: requires server support but
1051+
* works with all special files
1052+
*/
1053+
struct cifs_unix_set_info_args args = {
1054+
.mode = mode & ~current_umask(),
1055+
.ctime = NO_CHANGE_64,
1056+
.atime = NO_CHANGE_64,
1057+
.mtime = NO_CHANGE_64,
1058+
.device = dev,
1059+
};
1060+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1061+
args.uid = current_fsuid();
1062+
args.gid = current_fsgid();
1063+
} else {
1064+
args.uid = INVALID_UID; /* no change */
1065+
args.gid = INVALID_GID; /* no change */
1066+
}
1067+
rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
1068+
cifs_sb->local_nls,
1069+
cifs_remap(cifs_sb));
1070+
if (rc)
1071+
goto out;
1072+
1073+
rc = cifs_get_inode_info_unix(&newinode, full_path,
1074+
inode->i_sb, xid);
1075+
1076+
if (rc == 0)
1077+
d_instantiate(dentry, newinode);
1078+
goto out;
1079+
}
1080+
1081+
/*
1082+
* SMB1 SFU emulation: should work with all servers, but only
1083+
* support block and char device (no socket & fifo)
1084+
*/
1085+
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
1086+
goto out;
1087+
1088+
if (!S_ISCHR(mode) && !S_ISBLK(mode))
1089+
goto out;
1090+
1091+
cifs_dbg(FYI, "sfu compat create special file\n");
1092+
1093+
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
1094+
if (buf == NULL) {
1095+
rc = -ENOMEM;
1096+
goto out;
1097+
}
1098+
1099+
if (backup_cred(cifs_sb))
1100+
create_options |= CREATE_OPEN_BACKUP_INTENT;
1101+
1102+
oparms.tcon = tcon;
1103+
oparms.cifs_sb = cifs_sb;
1104+
oparms.desired_access = GENERIC_WRITE;
1105+
oparms.create_options = create_options;
1106+
oparms.disposition = FILE_CREATE;
1107+
oparms.path = full_path;
1108+
oparms.fid = &fid;
1109+
oparms.reconnect = false;
1110+
1111+
if (tcon->ses->server->oplocks)
1112+
oplock = REQ_OPLOCK;
1113+
else
1114+
oplock = 0;
1115+
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
1116+
if (rc)
1117+
goto out;
1118+
1119+
/*
1120+
* BB Do not bother to decode buf since no local inode yet to put
1121+
* timestamps in, but we can reuse it safely.
1122+
*/
1123+
1124+
pdev = (struct win_dev *)buf;
1125+
io_parms.pid = current->tgid;
1126+
io_parms.tcon = tcon;
1127+
io_parms.offset = 0;
1128+
io_parms.length = sizeof(struct win_dev);
1129+
iov[1].iov_base = buf;
1130+
iov[1].iov_len = sizeof(struct win_dev);
1131+
if (S_ISCHR(mode)) {
1132+
memcpy(pdev->type, "IntxCHR", 8);
1133+
pdev->major = cpu_to_le64(MAJOR(dev));
1134+
pdev->minor = cpu_to_le64(MINOR(dev));
1135+
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
1136+
&bytes_written, iov, 1);
1137+
} else if (S_ISBLK(mode)) {
1138+
memcpy(pdev->type, "IntxBLK", 8);
1139+
pdev->major = cpu_to_le64(MAJOR(dev));
1140+
pdev->minor = cpu_to_le64(MINOR(dev));
1141+
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
1142+
&bytes_written, iov, 1);
1143+
}
1144+
tcon->ses->server->ops->close(xid, tcon, &fid);
1145+
d_drop(dentry);
1146+
1147+
/* FIXME: add code here to set EAs */
1148+
out:
1149+
kfree(buf);
1150+
return rc;
1151+
}
1152+
1153+
1154+
10301155
struct smb_version_operations smb1_operations = {
10311156
.send_cancel = send_nt_cancel,
10321157
.compare_fids = cifs_compare_fids,
@@ -1110,6 +1235,7 @@ struct smb_version_operations smb1_operations = {
11101235
.get_acl_by_fid = get_cifs_acl_by_fid,
11111236
.set_acl = set_cifs_acl,
11121237
#endif /* CIFS_ACL */
1238+
.make_node = cifs_make_node,
11131239
};
11141240

11151241
struct smb_version_values smb1_values = {

0 commit comments

Comments
 (0)