aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2014-09-22 06:13:55 -0400
committerSteve French <smfrench@gmail.com>2014-10-16 16:20:19 -0400
commitdb8b631d4bc4eaa9f7e13a6b0a287306cac0cb72 (patch)
treee18c8eb5f156c9a201ba432e3c963c13110d8ad8
parent73322979097f287101617904dd08180feaa658b4 (diff)
Allow mknod and mkfifo on SMB2/SMB3 mounts
The "sfu" mount option did not work on SMB2/SMB3 mounts. With these changes when the "sfu" mount option is passed in on an smb2/smb2.1/smb3 mount the client can emulate (and recognize) fifo and device (character and device files). In addition the "sfu" mount option should not conflict with "mfsymlinks" (symlink emulation) as we will never create "sfu" style symlinks, but using "sfu" mount option will allow us to recognize existing symlinks, created with Microsoft "Services for Unix" (SFU and SUA). To enable the "sfu" mount option for SMB2/SMB3 the calling syntax of the generic cifs/smb2/smb3 sync_read and sync_write protocol dependent function needed to be changed (we don't have a file struct in all cases), but this actually ended up simplifying the code a little. Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r--fs/cifs/cifsglob.h4
-rw-r--r--fs/cifs/connect.c16
-rw-r--r--fs/cifs/dir.c22
-rw-r--r--fs/cifs/file.c6
-rw-r--r--fs/cifs/inode.c15
-rw-r--r--fs/cifs/smb1ops.c8
-rw-r--r--fs/cifs/smb2ops.c12
-rw-r--r--fs/cifs/smb2pdu.c2
8 files changed, 55 insertions, 30 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 25b8392bfdd2..dae7e3709cc6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -323,11 +323,11 @@ struct smb_version_operations {
323 int (*async_writev)(struct cifs_writedata *, 323 int (*async_writev)(struct cifs_writedata *,
324 void (*release)(struct kref *)); 324 void (*release)(struct kref *));
325 /* sync read from the server */ 325 /* sync read from the server */
326 int (*sync_read)(const unsigned int, struct cifsFileInfo *, 326 int (*sync_read)(const unsigned int, struct cifs_fid *,
327 struct cifs_io_parms *, unsigned int *, char **, 327 struct cifs_io_parms *, unsigned int *, char **,
328 int *); 328 int *);
329 /* sync write to the server */ 329 /* sync write to the server */
330 int (*sync_write)(const unsigned int, struct cifsFileInfo *, 330 int (*sync_write)(const unsigned int, struct cifs_fid *,
331 struct cifs_io_parms *, unsigned int *, struct kvec *, 331 struct cifs_io_parms *, unsigned int *, struct kvec *,
332 unsigned long); 332 unsigned long);
333 /* open dir, start readdir */ 333 /* open dir, start readdir */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 239e1fb33000..d8eb6a74b211 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3239,10 +3239,20 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3239 } 3239 }
3240 if (pvolume_info->mfsymlinks) { 3240 if (pvolume_info->mfsymlinks) {
3241 if (pvolume_info->sfu_emul) { 3241 if (pvolume_info->sfu_emul) {
3242 cifs_dbg(VFS, "mount option mfsymlinks ignored if sfu mount option is used\n"); 3242 /*
3243 } else { 3243 * Our SFU ("Services for Unix" emulation does not allow
3244 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; 3244 * creating symlinks but does allow reading existing SFU
3245 * symlinks (it does allow both creating and reading SFU
3246 * style mknod and FIFOs though). When "mfsymlinks" and
3247 * "sfu" are both enabled at the same time, it allows
3248 * reading both types of symlinks, but will only create
3249 * them with mfsymlinks format. This allows better
3250 * Apple compatibility (probably better for Samba too)
3251 * while still recognizing old Windows style symlinks.
3252 */
3253 cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
3245 } 3254 }
3255 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
3246 } 3256 }
3247 3257
3248 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) 3258 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 073640675a39..b72bc29cba23 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -577,12 +577,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
577 struct cifs_io_parms io_parms; 577 struct cifs_io_parms io_parms;
578 char *full_path = NULL; 578 char *full_path = NULL;
579 struct inode *newinode = NULL; 579 struct inode *newinode = NULL;
580 int oplock = 0; 580 __u32 oplock = 0;
581 struct cifs_fid fid; 581 struct cifs_fid fid;
582 struct cifs_open_parms oparms; 582 struct cifs_open_parms oparms;
583 FILE_ALL_INFO *buf = NULL; 583 FILE_ALL_INFO *buf = NULL;
584 unsigned int bytes_written; 584 unsigned int bytes_written;
585 struct win_dev *pdev; 585 struct win_dev *pdev;
586 struct kvec iov[2];
586 587
587 if (!old_valid_dev(device_number)) 588 if (!old_valid_dev(device_number))
588 return -EINVAL; 589 return -EINVAL;
@@ -658,7 +659,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
658 oparms.fid = &fid; 659 oparms.fid = &fid;
659 oparms.reconnect = false; 660 oparms.reconnect = false;
660 661
661 rc = CIFS_open(xid, &oparms, &oplock, buf); 662 if (tcon->ses->server->oplocks)
663 oplock = REQ_OPLOCK;
664 else
665 oplock = 0;
666 rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
662 if (rc) 667 if (rc)
663 goto mknod_out; 668 goto mknod_out;
664 669
@@ -668,25 +673,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
668 */ 673 */
669 674
670 pdev = (struct win_dev *)buf; 675 pdev = (struct win_dev *)buf;
671 io_parms.netfid = fid.netfid;
672 io_parms.pid = current->tgid; 676 io_parms.pid = current->tgid;
673 io_parms.tcon = tcon; 677 io_parms.tcon = tcon;
674 io_parms.offset = 0; 678 io_parms.offset = 0;
675 io_parms.length = sizeof(struct win_dev); 679 io_parms.length = sizeof(struct win_dev);
680 iov[1].iov_base = buf;
681 iov[1].iov_len = sizeof(struct win_dev);
676 if (S_ISCHR(mode)) { 682 if (S_ISCHR(mode)) {
677 memcpy(pdev->type, "IntxCHR", 8); 683 memcpy(pdev->type, "IntxCHR", 8);
678 pdev->major = cpu_to_le64(MAJOR(device_number)); 684 pdev->major = cpu_to_le64(MAJOR(device_number));
679 pdev->minor = cpu_to_le64(MINOR(device_number)); 685 pdev->minor = cpu_to_le64(MINOR(device_number));
680 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, 686 rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
681 NULL, 0); 687 &bytes_written, iov, 1);
682 } else if (S_ISBLK(mode)) { 688 } else if (S_ISBLK(mode)) {
683 memcpy(pdev->type, "IntxBLK", 8); 689 memcpy(pdev->type, "IntxBLK", 8);
684 pdev->major = cpu_to_le64(MAJOR(device_number)); 690 pdev->major = cpu_to_le64(MAJOR(device_number));
685 pdev->minor = cpu_to_le64(MINOR(device_number)); 691 pdev->minor = cpu_to_le64(MINOR(device_number));
686 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, 692 rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
687 NULL, 0); 693 &bytes_written, iov, 1);
688 } /* else if (S_ISFIFO) */ 694 } /* else if (S_ISFIFO) */
689 CIFSSMBClose(xid, tcon, fid.netfid); 695 tcon->ses->server->ops->close(xid, tcon, &fid);
690 d_drop(direntry); 696 d_drop(direntry);
691 697
692 /* FIXME: add code here to set EAs */ 698 /* FIXME: add code here to set EAs */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8f7b40fd8f3b..3e4d00a06c44 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1687,8 +1687,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
1687 io_parms.tcon = tcon; 1687 io_parms.tcon = tcon;
1688 io_parms.offset = *offset; 1688 io_parms.offset = *offset;
1689 io_parms.length = len; 1689 io_parms.length = len;
1690 rc = server->ops->sync_write(xid, open_file, &io_parms, 1690 rc = server->ops->sync_write(xid, &open_file->fid,
1691 &bytes_written, iov, 1); 1691 &io_parms, &bytes_written, iov, 1);
1692 } 1692 }
1693 if (rc || (bytes_written == 0)) { 1693 if (rc || (bytes_written == 0)) {
1694 if (total_written) 1694 if (total_written)
@@ -3206,7 +3206,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
3206 io_parms.tcon = tcon; 3206 io_parms.tcon = tcon;
3207 io_parms.offset = *offset; 3207 io_parms.offset = *offset;
3208 io_parms.length = current_read_size; 3208 io_parms.length = current_read_size;
3209 rc = server->ops->sync_read(xid, open_file, &io_parms, 3209 rc = server->ops->sync_read(xid, &open_file->fid, &io_parms,
3210 &bytes_read, &cur_offset, 3210 &bytes_read, &cur_offset,
3211 &buf_type); 3211 &buf_type);
3212 } while (rc == -EAGAIN); 3212 } while (rc == -EAGAIN);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8fd4ee8e07ff..4ff36ea8c693 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -412,7 +412,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
412 struct cifs_sb_info *cifs_sb, unsigned int xid) 412 struct cifs_sb_info *cifs_sb, unsigned int xid)
413{ 413{
414 int rc; 414 int rc;
415 int oplock = 0; 415 __u32 oplock;
416 struct tcon_link *tlink; 416 struct tcon_link *tlink;
417 struct cifs_tcon *tcon; 417 struct cifs_tcon *tcon;
418 struct cifs_fid fid; 418 struct cifs_fid fid;
@@ -451,8 +451,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
451 oparms.fid = &fid; 451 oparms.fid = &fid;
452 oparms.reconnect = false; 452 oparms.reconnect = false;
453 453
454 rc = CIFS_open(xid, &oparms, &oplock, NULL); 454 if (tcon->ses->server->oplocks)
455 oplock = REQ_OPLOCK;
456 else
457 oplock = 0;
458 rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
455 if (rc) { 459 if (rc) {
460 cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc);
456 cifs_put_tlink(tlink); 461 cifs_put_tlink(tlink);
457 return rc; 462 return rc;
458 } 463 }
@@ -464,7 +469,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
464 io_parms.offset = 0; 469 io_parms.offset = 0;
465 io_parms.length = 24; 470 io_parms.length = 24;
466 471
467 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); 472 rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
473 &bytes_read, &pbuf, &buf_type);
468 if ((rc == 0) && (bytes_read >= 8)) { 474 if ((rc == 0) && (bytes_read >= 8)) {
469 if (memcmp("IntxBLK", pbuf, 8) == 0) { 475 if (memcmp("IntxBLK", pbuf, 8) == 0) {
470 cifs_dbg(FYI, "Block device\n"); 476 cifs_dbg(FYI, "Block device\n");
@@ -504,7 +510,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
504 fattr->cf_dtype = DT_REG; 510 fattr->cf_dtype = DT_REG;
505 rc = -EOPNOTSUPP; /* or some unknown SFU type */ 511 rc = -EOPNOTSUPP; /* or some unknown SFU type */
506 } 512 }
507 CIFSSMBClose(xid, tcon, fid.netfid); 513
514 tcon->ses->server->ops->close(xid, tcon, &fid);
508 cifs_put_tlink(tlink); 515 cifs_put_tlink(tlink);
509 return rc; 516 return rc;
510} 517}
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 52131d8cb4d5..2aca620193cd 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -749,21 +749,21 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
749} 749}
750 750
751static int 751static int
752cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, 752cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid,
753 struct cifs_io_parms *parms, unsigned int *bytes_read, 753 struct cifs_io_parms *parms, unsigned int *bytes_read,
754 char **buf, int *buf_type) 754 char **buf, int *buf_type)
755{ 755{
756 parms->netfid = cfile->fid.netfid; 756 parms->netfid = pfid->netfid;
757 return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type); 757 return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
758} 758}
759 759
760static int 760static int
761cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, 761cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid,
762 struct cifs_io_parms *parms, unsigned int *written, 762 struct cifs_io_parms *parms, unsigned int *written,
763 struct kvec *iov, unsigned long nr_segs) 763 struct kvec *iov, unsigned long nr_segs)
764{ 764{
765 765
766 parms->netfid = cfile->fid.netfid; 766 parms->netfid = pfid->netfid;
767 return CIFSSMBWrite2(xid, parms, written, iov, nr_segs); 767 return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
768} 768}
769 769
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f522193b7184..ea158c9dea15 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -711,23 +711,23 @@ smb2_read_data_length(char *buf)
711 711
712 712
713static int 713static int
714smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, 714smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid,
715 struct cifs_io_parms *parms, unsigned int *bytes_read, 715 struct cifs_io_parms *parms, unsigned int *bytes_read,
716 char **buf, int *buf_type) 716 char **buf, int *buf_type)
717{ 717{
718 parms->persistent_fid = cfile->fid.persistent_fid; 718 parms->persistent_fid = pfid->persistent_fid;
719 parms->volatile_fid = cfile->fid.volatile_fid; 719 parms->volatile_fid = pfid->volatile_fid;
720 return SMB2_read(xid, parms, bytes_read, buf, buf_type); 720 return SMB2_read(xid, parms, bytes_read, buf, buf_type);
721} 721}
722 722
723static int 723static int
724smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, 724smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid,
725 struct cifs_io_parms *parms, unsigned int *written, 725 struct cifs_io_parms *parms, unsigned int *written,
726 struct kvec *iov, unsigned long nr_segs) 726 struct kvec *iov, unsigned long nr_segs)
727{ 727{
728 728
729 parms->persistent_fid = cfile->fid.persistent_fid; 729 parms->persistent_fid = pfid->persistent_fid;
730 parms->volatile_fid = cfile->fid.volatile_fid; 730 parms->volatile_fid = pfid->volatile_fid;
731 return SMB2_write(xid, parms, written, iov, nr_segs); 731 return SMB2_write(xid, parms, written, iov, nr_segs);
732} 732}
733 733
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 74b3a6684383..8f1672bb82d5 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1098,6 +1098,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1098 1098
1099 if (oparms->create_options & CREATE_OPTION_READONLY) 1099 if (oparms->create_options & CREATE_OPTION_READONLY)
1100 file_attributes |= ATTR_READONLY; 1100 file_attributes |= ATTR_READONLY;
1101 if (oparms->create_options & CREATE_OPTION_SPECIAL)
1102 file_attributes |= ATTR_SYSTEM;
1101 1103
1102 req->ImpersonationLevel = IL_IMPERSONATION; 1104 req->ImpersonationLevel = IL_IMPERSONATION;
1103 req->DesiredAccess = cpu_to_le32(oparms->desired_access); 1105 req->DesiredAccess = cpu_to_le32(oparms->desired_access);