hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/cifs/inode.c
....@@ -25,12 +25,14 @@
2525 #include <linux/freezer.h>
2626 #include <linux/sched/signal.h>
2727 #include <linux/wait_bit.h>
28
+#include <linux/fiemap.h>
2829
2930 #include <asm/div64.h>
3031 #include "cifsfs.h"
3132 #include "cifspdu.h"
3233 #include "cifsglob.h"
3334 #include "cifsproto.h"
35
+#include "smb2proto.h"
3436 #include "cifs_debug.h"
3537 #include "cifs_fs_sb.h"
3638 #include "cifs_unicode.h"
....@@ -61,7 +63,7 @@
6163 }
6264
6365 /* check if server can support readpages */
64
- if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
66
+ if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read <
6567 PAGE_SIZE + MAX_CIFS_HDR_SIZE)
6668 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
6769 else
....@@ -113,6 +115,7 @@
113115 }
114116
115117 /* revalidate if mtime or size have changed */
118
+ fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
116119 if (timespec64_equal(&inode->i_mtime, &fattr->cf_mtime) &&
117120 cifs_i->server_eof == fattr->cf_eof) {
118121 cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
....@@ -162,7 +165,14 @@
162165 cifs_revalidate_cache(inode, fattr);
163166
164167 spin_lock(&inode->i_lock);
165
- inode->i_atime = fattr->cf_atime;
168
+ fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
169
+ fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode);
170
+ fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode);
171
+ /* we do not want atime to be less than mtime, it broke some apps */
172
+ if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0)
173
+ inode->i_atime = fattr->cf_mtime;
174
+ else
175
+ inode->i_atime = fattr->cf_atime;
166176 inode->i_mtime = fattr->cf_mtime;
167177 inode->i_ctime = fattr->cf_ctime;
168178 inode->i_rdev = fattr->cf_rdev;
....@@ -325,11 +335,10 @@
325335 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
326336 fattr->cf_uid = cifs_sb->mnt_uid;
327337 fattr->cf_gid = cifs_sb->mnt_gid;
328
- ktime_get_real_ts64(&fattr->cf_mtime);
329
- fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran);
338
+ ktime_get_coarse_real_ts64(&fattr->cf_mtime);
330339 fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
331340 fattr->cf_nlink = 2;
332
- fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
341
+ fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
333342 }
334343
335344 static int
....@@ -351,9 +360,12 @@
351360 } else if (rc == -EREMOTE) {
352361 cifs_create_dfs_fattr(&fattr, inode->i_sb);
353362 rc = 0;
354
- }
363
+ } else
364
+ goto cifs_gfiunix_out;
355365
356366 cifs_fattr_to_inode(inode, &fattr);
367
+
368
+cifs_gfiunix_out:
357369 free_xid(xid);
358370 return rc;
359371 }
....@@ -416,8 +428,7 @@
416428 }
417429
418430 /* if filetype is different, return error */
419
- if (unlikely(((*pinode)->i_mode & S_IFMT) !=
420
- (fattr.cf_mode & S_IFMT))) {
431
+ if (unlikely(inode_wrong_type(*pinode, fattr.cf_mode))) {
421432 CIFS_I(*pinode)->time = 0; /* force reval */
422433 rc = -ESTALE;
423434 goto cgiiu_exit;
....@@ -440,7 +451,7 @@
440451 struct cifs_tcon *tcon;
441452 struct cifs_fid fid;
442453 struct cifs_open_parms oparms;
443
- struct cifs_io_parms io_parms;
454
+ struct cifs_io_parms io_parms = {0};
444455 char buf[24];
445456 unsigned int bytes_read;
446457 char *pbuf;
....@@ -468,9 +479,7 @@
468479 oparms.tcon = tcon;
469480 oparms.cifs_sb = cifs_sb;
470481 oparms.desired_access = GENERIC_READ;
471
- oparms.create_options = CREATE_NOT_DIR;
472
- if (backup_cred(cifs_sb))
473
- oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
482
+ oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
474483 oparms.disposition = FILE_OPEN;
475484 oparms.path = path;
476485 oparms.fid = &fid;
....@@ -589,11 +598,67 @@
589598 #endif
590599 }
591600
601
+/* Fill a cifs_fattr struct with info from POSIX info struct */
602
+static void
603
+smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *info,
604
+ struct super_block *sb, bool adjust_tz, bool symlink)
605
+{
606
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
607
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
608
+
609
+ memset(fattr, 0, sizeof(*fattr));
610
+
611
+ /* no fattr->flags to set */
612
+ fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
613
+ fattr->cf_uniqueid = le64_to_cpu(info->Inode);
614
+
615
+ if (info->LastAccessTime)
616
+ fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
617
+ else
618
+ ktime_get_coarse_real_ts64(&fattr->cf_atime);
619
+
620
+ fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
621
+ fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
622
+
623
+ if (adjust_tz) {
624
+ fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
625
+ fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
626
+ }
627
+
628
+ fattr->cf_eof = le64_to_cpu(info->EndOfFile);
629
+ fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
630
+ fattr->cf_createtime = le64_to_cpu(info->CreationTime);
631
+
632
+ fattr->cf_nlink = le32_to_cpu(info->HardLinks);
633
+ fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode);
634
+ /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */
635
+ /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */
636
+
637
+ if (symlink) {
638
+ fattr->cf_mode |= S_IFLNK;
639
+ fattr->cf_dtype = DT_LNK;
640
+ } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
641
+ fattr->cf_mode |= S_IFDIR;
642
+ fattr->cf_dtype = DT_DIR;
643
+ } else { /* file */
644
+ fattr->cf_mode |= S_IFREG;
645
+ fattr->cf_dtype = DT_REG;
646
+ }
647
+ /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */
648
+
649
+ fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */
650
+ fattr->cf_gid = cifs_sb->mnt_gid;
651
+
652
+ cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
653
+ fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
654
+}
655
+
656
+
592657 /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
593658 static void
594659 cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
595660 struct super_block *sb, bool adjust_tz,
596
- bool symlink)
661
+ bool symlink, u32 reparse_tag)
597662 {
598663 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
599664 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
....@@ -605,10 +670,8 @@
605670
606671 if (info->LastAccessTime)
607672 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
608
- else {
609
- ktime_get_real_ts64(&fattr->cf_atime);
610
- fattr->cf_atime = timespec64_trunc(fattr->cf_atime, sb->s_time_gran);
611
- }
673
+ else
674
+ ktime_get_coarse_real_ts64(&fattr->cf_atime);
612675
613676 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
614677 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
....@@ -623,8 +686,22 @@
623686 fattr->cf_createtime = le64_to_cpu(info->CreationTime);
624687
625688 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
626
-
627
- if (symlink) {
689
+ if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
690
+ fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode;
691
+ fattr->cf_dtype = DT_LNK;
692
+ } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
693
+ fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode;
694
+ fattr->cf_dtype = DT_FIFO;
695
+ } else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
696
+ fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode;
697
+ fattr->cf_dtype = DT_SOCK;
698
+ } else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
699
+ fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode;
700
+ fattr->cf_dtype = DT_CHR;
701
+ } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
702
+ fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode;
703
+ fattr->cf_dtype = DT_BLK;
704
+ } else if (symlink) { /* TODO add more reparse tag checks */
628705 fattr->cf_mode = S_IFLNK;
629706 fattr->cf_dtype = DT_LNK;
630707 } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
....@@ -650,8 +727,8 @@
650727 */
651728 if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
652729 !info->DeletePending) {
653
- cifs_dbg(1, "bogus file nlink value %u\n",
654
- fattr->cf_nlink);
730
+ cifs_dbg(VFS, "bogus file nlink value %u\n",
731
+ fattr->cf_nlink);
655732 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
656733 }
657734 }
....@@ -679,8 +756,9 @@
679756 rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
680757 switch (rc) {
681758 case 0:
759
+ /* TODO: add support to query reparse tag */
682760 cifs_all_info_to_fattr(&fattr, &find_data, inode->i_sb, false,
683
- false);
761
+ false, 0 /* no reparse tag */);
684762 break;
685763 case -EREMOTE:
686764 cifs_create_dfs_fattr(&fattr, inode->i_sb);
....@@ -723,23 +801,139 @@
723801 return hash;
724802 }
725803
804
+/**
805
+ * cifs_backup_query_path_info - SMB1 fallback code to get ino
806
+ *
807
+ * Fallback code to get file metadata when we don't have access to
808
+ * @full_path (EACCES) and have backup creds.
809
+ *
810
+ * @data will be set to search info result buffer
811
+ * @resp_buf will be set to cifs resp buf and needs to be freed with
812
+ * cifs_buf_release() when done with @data.
813
+ */
814
+static int
815
+cifs_backup_query_path_info(int xid,
816
+ struct cifs_tcon *tcon,
817
+ struct super_block *sb,
818
+ const char *full_path,
819
+ void **resp_buf,
820
+ FILE_ALL_INFO **data)
821
+{
822
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
823
+ struct cifs_search_info info = {0};
824
+ u16 flags;
825
+ int rc;
826
+
827
+ *resp_buf = NULL;
828
+ info.endOfSearch = false;
829
+ if (tcon->unix_ext)
830
+ info.info_level = SMB_FIND_FILE_UNIX;
831
+ else if ((tcon->ses->capabilities &
832
+ tcon->ses->server->vals->cap_nt_find) == 0)
833
+ info.info_level = SMB_FIND_FILE_INFO_STANDARD;
834
+ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
835
+ info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
836
+ else /* no srvino useful for fallback to some netapp */
837
+ info.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
838
+
839
+ flags = CIFS_SEARCH_CLOSE_ALWAYS |
840
+ CIFS_SEARCH_CLOSE_AT_END |
841
+ CIFS_SEARCH_BACKUP_SEARCH;
842
+
843
+ rc = CIFSFindFirst(xid, tcon, full_path,
844
+ cifs_sb, NULL, flags, &info, false);
845
+ if (rc)
846
+ return rc;
847
+
848
+ *resp_buf = (void *)info.ntwrk_buf_start;
849
+ *data = (FILE_ALL_INFO *)info.srch_entries_start;
850
+ return 0;
851
+}
852
+
853
+static void
854
+cifs_set_fattr_ino(int xid,
855
+ struct cifs_tcon *tcon,
856
+ struct super_block *sb,
857
+ struct inode **inode,
858
+ const char *full_path,
859
+ FILE_ALL_INFO *data,
860
+ struct cifs_fattr *fattr)
861
+{
862
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
863
+ struct TCP_Server_Info *server = tcon->ses->server;
864
+ int rc;
865
+
866
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
867
+ if (*inode)
868
+ fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
869
+ else
870
+ fattr->cf_uniqueid = iunique(sb, ROOT_I);
871
+ return;
872
+ }
873
+
874
+ /*
875
+ * If we have an inode pass a NULL tcon to ensure we don't
876
+ * make a round trip to the server. This only works for SMB2+.
877
+ */
878
+ rc = server->ops->get_srv_inum(xid,
879
+ *inode ? NULL : tcon,
880
+ cifs_sb, full_path,
881
+ &fattr->cf_uniqueid,
882
+ data);
883
+ if (rc) {
884
+ /*
885
+ * If that fails reuse existing ino or generate one
886
+ * and disable server ones
887
+ */
888
+ if (*inode)
889
+ fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
890
+ else {
891
+ fattr->cf_uniqueid = iunique(sb, ROOT_I);
892
+ cifs_autodisable_serverino(cifs_sb);
893
+ }
894
+ return;
895
+ }
896
+
897
+ /* If no errors, check for zero root inode (invalid) */
898
+ if (fattr->cf_uniqueid == 0 && strlen(full_path) == 0) {
899
+ cifs_dbg(FYI, "Invalid (0) inodenum\n");
900
+ if (*inode) {
901
+ /* reuse */
902
+ fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
903
+ } else {
904
+ /* make an ino by hashing the UNC */
905
+ fattr->cf_flags |= CIFS_FATTR_FAKE_ROOT_INO;
906
+ fattr->cf_uniqueid = simple_hashstr(tcon->treeName);
907
+ }
908
+ }
909
+}
910
+
911
+static inline bool is_inode_cache_good(struct inode *ino)
912
+{
913
+ return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
914
+}
915
+
726916 int
727
-cifs_get_inode_info(struct inode **inode, const char *full_path,
728
- FILE_ALL_INFO *data, struct super_block *sb, int xid,
917
+cifs_get_inode_info(struct inode **inode,
918
+ const char *full_path,
919
+ FILE_ALL_INFO *in_data,
920
+ struct super_block *sb, int xid,
729921 const struct cifs_fid *fid)
730922 {
731
- bool validinum = false;
732
- __u16 srchflgs;
733
- int rc = 0, tmprc = ENOSYS;
923
+
734924 struct cifs_tcon *tcon;
735925 struct TCP_Server_Info *server;
736926 struct tcon_link *tlink;
737927 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
738
- char *buf = NULL;
739928 bool adjust_tz = false;
740
- struct cifs_fattr fattr;
741
- struct cifs_search_info *srchinf = NULL;
742
- bool symlink = false;
929
+ struct cifs_fattr fattr = {0};
930
+ bool is_reparse_point = false;
931
+ FILE_ALL_INFO *data = in_data;
932
+ FILE_ALL_INFO *tmp_data = NULL;
933
+ void *smb1_backup_rsp_buf = NULL;
934
+ int rc = 0;
935
+ int tmprc = 0;
936
+ __u32 reparse_tag = 0;
743937
744938 tlink = cifs_sb_tlink(cifs_sb);
745939 if (IS_ERR(tlink))
....@@ -747,145 +941,100 @@
747941 tcon = tlink_tcon(tlink);
748942 server = tcon->ses->server;
749943
750
- cifs_dbg(FYI, "Getting info on %s\n", full_path);
944
+ /*
945
+ * 1. Fetch file metadata if not provided (data)
946
+ */
751947
752
- if ((data == NULL) && (*inode != NULL)) {
753
- if (CIFS_CACHE_READ(CIFS_I(*inode)) &&
754
- CIFS_I(*inode)->time != 0) {
948
+ if (!data) {
949
+ if (is_inode_cache_good(*inode)) {
755950 cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
756
- goto cgii_exit;
951
+ goto out;
757952 }
758
- }
759
-
760
- /* if inode info is not passed, get it from server */
761
- if (data == NULL) {
762
- if (!server->ops->query_path_info) {
763
- rc = -ENOSYS;
764
- goto cgii_exit;
765
- }
766
- buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
767
- if (buf == NULL) {
953
+ tmp_data = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
954
+ if (!tmp_data) {
768955 rc = -ENOMEM;
769
- goto cgii_exit;
956
+ goto out;
770957 }
771
- data = (FILE_ALL_INFO *)buf;
772
- rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path,
773
- data, &adjust_tz, &symlink);
958
+ rc = server->ops->query_path_info(xid, tcon, cifs_sb,
959
+ full_path, tmp_data,
960
+ &adjust_tz, &is_reparse_point);
961
+ data = tmp_data;
774962 }
775
-
776
- if (!rc) {
777
- cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz,
778
- symlink);
779
- } else if (rc == -EREMOTE) {
780
- cifs_create_dfs_fattr(&fattr, sb);
781
- rc = 0;
782
- } else if ((rc == -EACCES) && backup_cred(cifs_sb) &&
783
- (strcmp(server->vals->version_string, SMB1_VERSION_STRING)
784
- == 0)) {
785
- /*
786
- * For SMB2 and later the backup intent flag is already
787
- * sent if needed on open and there is no path based
788
- * FindFirst operation to use to retry with
789
- */
790
-
791
- srchinf = kzalloc(sizeof(struct cifs_search_info),
792
- GFP_KERNEL);
793
- if (srchinf == NULL) {
794
- rc = -ENOMEM;
795
- goto cgii_exit;
796
- }
797
-
798
- srchinf->endOfSearch = false;
799
- if (tcon->unix_ext)
800
- srchinf->info_level = SMB_FIND_FILE_UNIX;
801
- else if ((tcon->ses->capabilities &
802
- tcon->ses->server->vals->cap_nt_find) == 0)
803
- srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD;
804
- else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
805
- srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
806
- else /* no srvino useful for fallback to some netapp */
807
- srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
808
-
809
- srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
810
- CIFS_SEARCH_CLOSE_AT_END |
811
- CIFS_SEARCH_BACKUP_SEARCH;
812
-
813
- rc = CIFSFindFirst(xid, tcon, full_path,
814
- cifs_sb, NULL, srchflgs, srchinf, false);
815
- if (!rc) {
816
- data = (FILE_ALL_INFO *)srchinf->srch_entries_start;
817
-
818
- cifs_dir_info_to_fattr(&fattr,
819
- (FILE_DIRECTORY_INFO *)data, cifs_sb);
820
- fattr.cf_uniqueid = le64_to_cpu(
821
- ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
822
- validinum = true;
823
-
824
- cifs_buf_release(srchinf->ntwrk_buf_start);
825
- }
826
- kfree(srchinf);
827
- if (rc)
828
- goto cgii_exit;
829
- } else
830
- goto cgii_exit;
831963
832964 /*
833
- * If an inode wasn't passed in, then get the inode number
834
- *
835
- * Is an i_ino of zero legal? Can we use that to check if the server
836
- * supports returning inode numbers? Are there other sanity checks we
837
- * can use to ensure that the server is really filling in that field?
965
+ * 2. Convert it to internal cifs metadata (fattr)
838966 */
839
- if (*inode == NULL) {
840
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
841
- if (validinum == false) {
842
- if (server->ops->get_srv_inum)
843
- tmprc = server->ops->get_srv_inum(xid,
844
- tcon, cifs_sb, full_path,
845
- &fattr.cf_uniqueid, data);
846
- if (tmprc) {
847
- cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
848
- tmprc);
849
- fattr.cf_uniqueid = iunique(sb, ROOT_I);
850
- cifs_autodisable_serverino(cifs_sb);
851
- } else if ((fattr.cf_uniqueid == 0) &&
852
- strlen(full_path) == 0) {
853
- /* some servers ret bad root ino ie 0 */
854
- cifs_dbg(FYI, "Invalid (0) inodenum\n");
855
- fattr.cf_flags |=
856
- CIFS_FATTR_FAKE_ROOT_INO;
857
- fattr.cf_uniqueid =
858
- simple_hashstr(tcon->treeName);
859
- }
860
- }
861
- } else
862
- fattr.cf_uniqueid = iunique(sb, ROOT_I);
863
- } else {
864
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
865
- validinum == false && server->ops->get_srv_inum) {
866
- /*
867
- * Pass a NULL tcon to ensure we don't make a round
868
- * trip to the server. This only works for SMB2+.
869
- */
870
- tmprc = server->ops->get_srv_inum(xid,
871
- NULL, cifs_sb, full_path,
872
- &fattr.cf_uniqueid, data);
873
- if (tmprc)
874
- fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
875
- else if ((fattr.cf_uniqueid == 0) &&
876
- strlen(full_path) == 0) {
877
- /*
878
- * Reuse existing root inode num since
879
- * inum zero for root causes ls of . and .. to
880
- * not be returned
881
- */
882
- cifs_dbg(FYI, "Srv ret 0 inode num for root\n");
883
- fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
884
- }
885
- } else
886
- fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
967
+
968
+ switch (rc) {
969
+ case 0:
970
+ /*
971
+ * If the file is a reparse point, it is more complicated
972
+ * since we have to check if its reparse tag matches a known
973
+ * special file type e.g. symlink or fifo or char etc.
974
+ */
975
+ if ((le32_to_cpu(data->Attributes) & ATTR_REPARSE) &&
976
+ server->ops->query_reparse_tag) {
977
+ rc = server->ops->query_reparse_tag(xid, tcon, cifs_sb,
978
+ full_path, &reparse_tag);
979
+ cifs_dbg(FYI, "reparse tag 0x%x\n", reparse_tag);
980
+ }
981
+ cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz,
982
+ is_reparse_point, reparse_tag);
983
+ break;
984
+ case -EREMOTE:
985
+ /* DFS link, no metadata available on this server */
986
+ cifs_create_dfs_fattr(&fattr, sb);
987
+ rc = 0;
988
+ break;
989
+ case -EACCES:
990
+ /*
991
+ * perm errors, try again with backup flags if possible
992
+ *
993
+ * For SMB2 and later the backup intent flag
994
+ * is already sent if needed on open and there
995
+ * is no path based FindFirst operation to use
996
+ * to retry with
997
+ */
998
+ if (backup_cred(cifs_sb) && is_smb1_server(server)) {
999
+ /* for easier reading */
1000
+ FILE_DIRECTORY_INFO *fdi;
1001
+ SEARCH_ID_FULL_DIR_INFO *si;
1002
+
1003
+ rc = cifs_backup_query_path_info(xid, tcon, sb,
1004
+ full_path,
1005
+ &smb1_backup_rsp_buf,
1006
+ &data);
1007
+ if (rc)
1008
+ goto out;
1009
+
1010
+ fdi = (FILE_DIRECTORY_INFO *)data;
1011
+ si = (SEARCH_ID_FULL_DIR_INFO *)data;
1012
+
1013
+ cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb);
1014
+ fattr.cf_uniqueid = le64_to_cpu(si->UniqueId);
1015
+ /* uniqueid set, skip get inum step */
1016
+ goto handle_mnt_opt;
1017
+ } else {
1018
+ /* nothing we can do, bail out */
1019
+ goto out;
1020
+ }
1021
+ break;
1022
+ default:
1023
+ cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc);
1024
+ goto out;
8871025 }
8881026
1027
+ /*
1028
+ * 3. Get or update inode number (fattr.cf_uniqueid)
1029
+ */
1030
+
1031
+ cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr);
1032
+
1033
+ /*
1034
+ * 4. Tweak fattr based on mount options
1035
+ */
1036
+
1037
+handle_mnt_opt:
8891038 /* query for SFU type info if supported and needed */
8901039 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
8911040 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
....@@ -894,17 +1043,28 @@
8941043 cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
8951044 }
8961045
897
-#ifdef CONFIG_CIFS_ACL
8981046 /* fill in 0777 bits from ACL */
899
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
900
- rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
1047
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
1048
+ rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
1049
+ full_path, fid);
1050
+ if (rc == -EREMOTE)
1051
+ rc = 0;
1052
+ if (rc) {
1053
+ cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n",
1054
+ __func__, rc);
1055
+ goto out;
1056
+ }
1057
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
1058
+ rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
1059
+ full_path, fid);
1060
+ if (rc == -EREMOTE)
1061
+ rc = 0;
9011062 if (rc) {
9021063 cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
9031064 __func__, rc);
904
- goto cgii_exit;
1065
+ goto out;
9051066 }
9061067 }
907
-#endif /* CONFIG_CIFS_ACL */
9081068
9091069 /* fill in remaining high mode bits e.g. SUID, VTX */
9101070 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
....@@ -918,6 +1078,10 @@
9181078 cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
9191079 }
9201080
1081
+ /*
1082
+ * 5. Update inode with final fattr data
1083
+ */
1084
+
9211085 if (!*inode) {
9221086 *inode = cifs_iget(sb, &fattr);
9231087 if (!*inode)
....@@ -930,7 +1094,7 @@
9301094 CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
9311095 CIFS_I(*inode)->time = 0; /* force reval */
9321096 rc = -ESTALE;
933
- goto cgii_exit;
1097
+ goto out;
9341098 }
9351099
9361100 /* if filetype is different, return error */
....@@ -938,20 +1102,130 @@
9381102 (fattr.cf_mode & S_IFMT))) {
9391103 CIFS_I(*inode)->time = 0; /* force reval */
9401104 rc = -ESTALE;
941
- goto cgii_exit;
1105
+ goto out;
9421106 }
9431107
9441108 cifs_fattr_to_inode(*inode, &fattr);
9451109 }
946
-
947
-cgii_exit:
948
- if ((*inode) && ((*inode)->i_ino == 0))
949
- cifs_dbg(FYI, "inode number of zero returned\n");
950
-
951
- kfree(buf);
1110
+out:
1111
+ cifs_buf_release(smb1_backup_rsp_buf);
9521112 cifs_put_tlink(tlink);
1113
+ kfree(tmp_data);
9531114 return rc;
9541115 }
1116
+
1117
+int
1118
+smb311_posix_get_inode_info(struct inode **inode,
1119
+ const char *full_path,
1120
+ struct super_block *sb, unsigned int xid)
1121
+{
1122
+ struct cifs_tcon *tcon;
1123
+ struct tcon_link *tlink;
1124
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1125
+ bool adjust_tz = false;
1126
+ struct cifs_fattr fattr = {0};
1127
+ bool symlink = false;
1128
+ struct smb311_posix_qinfo *data = NULL;
1129
+ int rc = 0;
1130
+ int tmprc = 0;
1131
+
1132
+ tlink = cifs_sb_tlink(cifs_sb);
1133
+ if (IS_ERR(tlink))
1134
+ return PTR_ERR(tlink);
1135
+ tcon = tlink_tcon(tlink);
1136
+
1137
+ /*
1138
+ * 1. Fetch file metadata
1139
+ */
1140
+
1141
+ if (is_inode_cache_good(*inode)) {
1142
+ cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
1143
+ goto out;
1144
+ }
1145
+ data = kmalloc(sizeof(struct smb311_posix_qinfo), GFP_KERNEL);
1146
+ if (!data) {
1147
+ rc = -ENOMEM;
1148
+ goto out;
1149
+ }
1150
+
1151
+ rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
1152
+ full_path, data,
1153
+ &adjust_tz, &symlink);
1154
+
1155
+ /*
1156
+ * 2. Convert it to internal cifs metadata (fattr)
1157
+ */
1158
+
1159
+ switch (rc) {
1160
+ case 0:
1161
+ smb311_posix_info_to_fattr(&fattr, data, sb, adjust_tz, symlink);
1162
+ break;
1163
+ case -EREMOTE:
1164
+ /* DFS link, no metadata available on this server */
1165
+ cifs_create_dfs_fattr(&fattr, sb);
1166
+ rc = 0;
1167
+ break;
1168
+ case -EACCES:
1169
+ /*
1170
+ * For SMB2 and later the backup intent flag
1171
+ * is already sent if needed on open and there
1172
+ * is no path based FindFirst operation to use
1173
+ * to retry with so nothing we can do, bail out
1174
+ */
1175
+ goto out;
1176
+ default:
1177
+ cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc);
1178
+ goto out;
1179
+ }
1180
+
1181
+
1182
+ /*
1183
+ * 3. Tweak fattr based on mount options
1184
+ */
1185
+
1186
+ /* check for Minshall+French symlinks */
1187
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
1188
+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
1189
+ full_path);
1190
+ if (tmprc)
1191
+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
1192
+ }
1193
+
1194
+ /*
1195
+ * 4. Update inode with final fattr data
1196
+ */
1197
+
1198
+ if (!*inode) {
1199
+ *inode = cifs_iget(sb, &fattr);
1200
+ if (!*inode)
1201
+ rc = -ENOMEM;
1202
+ } else {
1203
+ /* we already have inode, update it */
1204
+
1205
+ /* if uniqueid is different, return error */
1206
+ if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
1207
+ CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
1208
+ CIFS_I(*inode)->time = 0; /* force reval */
1209
+ rc = -ESTALE;
1210
+ goto out;
1211
+ }
1212
+
1213
+ /* if filetype is different, return error */
1214
+ if (unlikely(((*inode)->i_mode & S_IFMT) !=
1215
+ (fattr.cf_mode & S_IFMT))) {
1216
+ CIFS_I(*inode)->time = 0; /* force reval */
1217
+ rc = -ESTALE;
1218
+ goto out;
1219
+ }
1220
+
1221
+ cifs_fattr_to_inode(*inode, &fattr);
1222
+ }
1223
+out:
1224
+ cifs_put_tlink(tlink);
1225
+ kfree(data);
1226
+ return rc;
1227
+}
1228
+
9551229
9561230 static const struct inode_operations cifs_ipc_inode_ops = {
9571231 .lookup = cifs_lookup,
....@@ -971,7 +1245,7 @@
9711245 return 0;
9721246
9731247 /* don't match inode of different type */
974
- if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
1248
+ if (inode_wrong_type(inode, fattr->cf_mode))
9751249 return 0;
9761250
9771251 /* if it's not a directory or has no dentries, then flag it */
....@@ -1086,12 +1360,15 @@
10861360 /* some servers mistakenly claim POSIX support */
10871361 if (rc != -EOPNOTSUPP)
10881362 goto iget_no_retry;
1089
- cifs_dbg(VFS, "server does not support POSIX extensions");
1363
+ cifs_dbg(VFS, "server does not support POSIX extensions\n");
10901364 tcon->unix_ext = false;
10911365 }
10921366
10931367 convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
1094
- rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
1368
+ if (tcon->posix_extensions)
1369
+ rc = smb311_posix_get_inode_info(&inode, path, sb, xid);
1370
+ else
1371
+ rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
10951372
10961373 iget_no_retry:
10971374 if (!inode) {
....@@ -1214,7 +1491,7 @@
12141491 oparms.tcon = tcon;
12151492 oparms.cifs_sb = cifs_sb;
12161493 oparms.desired_access = DELETE | FILE_WRITE_ATTRIBUTES;
1217
- oparms.create_options = CREATE_NOT_DIR;
1494
+ oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
12181495 oparms.disposition = FILE_OPEN;
12191496 oparms.path = full_path;
12201497 oparms.fid = &fid;
....@@ -1320,8 +1597,8 @@
13201597 /*
13211598 * If d_inode(dentry) is null (usually meaning the cached dentry
13221599 * is a negative dentry) then we would attempt a standard SMB delete, but
1323
- * if that fails we can not attempt the fall back mechanisms on EACCESS
1324
- * but will return the EACCESS to the caller. Note that the VFS does not call
1600
+ * if that fails we can not attempt the fall back mechanisms on EACCES
1601
+ * but will return the EACCES to the caller. Note that the VFS does not call
13251602 * unlink on negative dentries currently.
13261603 */
13271604 int cifs_unlink(struct inode *dir, struct dentry *dentry)
....@@ -1348,6 +1625,11 @@
13481625 server = tcon->ses->server;
13491626
13501627 xid = get_xid();
1628
+
1629
+ if (tcon->nodelete) {
1630
+ rc = -EACCES;
1631
+ goto unlink_out;
1632
+ }
13511633
13521634 /* Unlink can be called from rename so we can not take the
13531635 * sb->s_vfs_rename_mutex here */
....@@ -1442,7 +1724,9 @@
14421724 int rc = 0;
14431725 struct inode *inode = NULL;
14441726
1445
- if (tcon->unix_ext)
1727
+ if (tcon->posix_extensions)
1728
+ rc = smb311_posix_get_inode_info(&inode, full_path, parent->i_sb, xid);
1729
+ else if (tcon->unix_ext)
14461730 rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb,
14471731 xid);
14481732 else
....@@ -1619,13 +1903,14 @@
16191903 }
16201904
16211905 /* BB add setting the equivalent of mode via CreateX w/ACLs */
1622
- rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
1906
+ rc = server->ops->mkdir(xid, inode, mode, tcon, full_path, cifs_sb);
16231907 if (rc) {
16241908 cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc);
16251909 d_drop(direntry);
16261910 goto mkdir_out;
16271911 }
16281912
1913
+ /* TODO: skip this for smb2/smb3 */
16291914 rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
16301915 xid);
16311916 mkdir_out:
....@@ -1672,6 +1957,12 @@
16721957
16731958 if (!server->ops->rmdir) {
16741959 rc = -ENOSYS;
1960
+ cifs_put_tlink(tlink);
1961
+ goto rmdir_exit;
1962
+ }
1963
+
1964
+ if (tcon->nodelete) {
1965
+ rc = -EACCES;
16751966 cifs_put_tlink(tlink);
16761967 goto rmdir_exit;
16771968 }
....@@ -1751,7 +2042,7 @@
17512042 oparms.cifs_sb = cifs_sb;
17522043 /* open the file to be renamed -- we need DELETE perms */
17532044 oparms.desired_access = DELETE;
1754
- oparms.create_options = CREATE_NOT_DIR;
2045
+ oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
17552046 oparms.disposition = FILE_OPEN;
17562047 oparms.path = from_path;
17572048 oparms.fid = &fid;
....@@ -1765,6 +2056,8 @@
17652056 CIFSSMBClose(xid, tcon, fid.netfid);
17662057 }
17672058 do_rename_exit:
2059
+ if (rc == 0)
2060
+ d_move(from_dentry, to_dentry);
17682061 cifs_put_tlink(tlink);
17692062 return rc;
17702063 }
....@@ -1927,7 +2220,7 @@
19272220 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
19282221 rc = invalidate_inode_pages2(inode->i_mapping);
19292222 if (rc)
1930
- cifs_dbg(VFS, "%s: could not invalidate inode %p\n",
2223
+ cifs_dbg(VFS, "%s: Could not invalidate inode %p\n",
19312224 __func__, inode);
19322225 }
19332226
....@@ -1953,6 +2246,10 @@
19532246 {
19542247 int rc;
19552248 unsigned long *flags = &CIFS_I(inode)->flags;
2249
+
2250
+ /* swapfiles are not supposed to be shared */
2251
+ if (IS_SWAPFILE(inode))
2252
+ return 0;
19562253
19572254 rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable,
19582255 TASK_KILLABLE);
....@@ -2026,7 +2323,9 @@
20262323 dentry, cifs_get_time(dentry), jiffies);
20272324
20282325 again:
2029
- if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
2326
+ if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions)
2327
+ rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid);
2328
+ else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
20302329 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
20312330 else
20322331 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
....@@ -2078,8 +2377,9 @@
20782377 * We need to be sure that all dirty pages are written and the server
20792378 * has actual ctime, mtime and file length.
20802379 */
2081
- if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
2082
- inode->i_mapping->nrpages != 0) {
2380
+ if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) &&
2381
+ !CIFS_CACHE_READ(CIFS_I(inode)) &&
2382
+ inode->i_mapping && inode->i_mapping->nrpages != 0) {
20832383 rc = filemap_fdatawait(inode->i_mapping);
20842384 if (rc) {
20852385 mapping_set_error(inode->i_mapping, rc);
....@@ -2087,12 +2387,23 @@
20872387 }
20882388 }
20892389
2090
- rc = cifs_revalidate_dentry_attr(dentry);
2091
- if (rc)
2092
- return rc;
2390
+ if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC)
2391
+ CIFS_I(inode)->time = 0; /* force revalidate */
2392
+
2393
+ /*
2394
+ * If the caller doesn't require syncing, only sync if
2395
+ * necessary (e.g. due to earlier truncate or setattr
2396
+ * invalidating the cached metadata)
2397
+ */
2398
+ if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) ||
2399
+ (CIFS_I(inode)->time == 0)) {
2400
+ rc = cifs_revalidate_dentry_attr(dentry);
2401
+ if (rc)
2402
+ return rc;
2403
+ }
20932404
20942405 generic_fillattr(inode, stat);
2095
- stat->blksize = CIFS_MAX_MSGSIZE;
2406
+ stat->blksize = cifs_sb->bsize;
20962407 stat->ino = CIFS_I(inode)->uniqueid;
20972408
20982409 /* old CIFS Unix Extensions doesn't return create time */
....@@ -2121,10 +2432,47 @@
21212432 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
21222433 stat->gid = current_fsgid();
21232434 }
2124
- return rc;
2435
+ return 0;
21252436 }
21262437
2127
-static int cifs_truncate_page(struct address_space *mapping, loff_t from)
2438
+int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
2439
+ u64 len)
2440
+{
2441
+ struct cifsInodeInfo *cifs_i = CIFS_I(inode);
2442
+ struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->vfs_inode.i_sb);
2443
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
2444
+ struct TCP_Server_Info *server = tcon->ses->server;
2445
+ struct cifsFileInfo *cfile;
2446
+ int rc;
2447
+
2448
+ /*
2449
+ * We need to be sure that all dirty pages are written as they
2450
+ * might fill holes on the server.
2451
+ */
2452
+ if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
2453
+ inode->i_mapping->nrpages != 0) {
2454
+ rc = filemap_fdatawait(inode->i_mapping);
2455
+ if (rc) {
2456
+ mapping_set_error(inode->i_mapping, rc);
2457
+ return rc;
2458
+ }
2459
+ }
2460
+
2461
+ cfile = find_readable_file(cifs_i, false);
2462
+ if (cfile == NULL)
2463
+ return -EINVAL;
2464
+
2465
+ if (server->ops->fiemap) {
2466
+ rc = server->ops->fiemap(tcon, cfile, fei, start, len);
2467
+ cifsFileInfo_put(cfile);
2468
+ return rc;
2469
+ }
2470
+
2471
+ cifsFileInfo_put(cfile);
2472
+ return -ENOTSUPP;
2473
+}
2474
+
2475
+int cifs_truncate_page(struct address_space *mapping, loff_t from)
21282476 {
21292477 pgoff_t index = from >> PAGE_SHIFT;
21302478 unsigned offset = from & (PAGE_SIZE - 1);
....@@ -2141,7 +2489,7 @@
21412489 return rc;
21422490 }
21432491
2144
-static void cifs_setsize(struct inode *inode, loff_t offset)
2492
+void cifs_setsize(struct inode *inode, loff_t offset)
21452493 {
21462494 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
21472495
....@@ -2175,7 +2523,7 @@
21752523 * writebehind data than the SMB timeout for the SetPathInfo
21762524 * request would allow
21772525 */
2178
- open_file = find_writable_file(cifsInode, true);
2526
+ open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
21792527 if (open_file) {
21802528 tcon = tlink_tcon(open_file->tlink);
21812529 server = tcon->ses->server;
....@@ -2219,6 +2567,14 @@
22192567 if (rc == 0) {
22202568 cifsInode->server_eof = attrs->ia_size;
22212569 cifs_setsize(inode, attrs->ia_size);
2570
+ /*
2571
+ * i_blocks is not related to (i_size / i_blksize), but instead
2572
+ * 512 byte (2**9) size is required for calculating num blocks.
2573
+ * Until we can query the server for actual allocation size,
2574
+ * this is best estimate we have for blocks allocated for a file
2575
+ * Number of blocks must be rounded up so size 1 is not 0 blocks
2576
+ */
2577
+ inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9;
22222578
22232579 /*
22242580 * The man page of truncate says if the size changed,
....@@ -2334,7 +2690,7 @@
23342690 args->ctime = NO_CHANGE_64;
23352691
23362692 args->device = 0;
2337
- open_file = find_writable_file(cifsInode, true);
2693
+ open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
23382694 if (open_file) {
23392695 u16 nfid = open_file->fid.netfid;
23402696 u32 npid = open_file->pid;
....@@ -2388,6 +2744,8 @@
23882744 struct inode *inode = d_inode(direntry);
23892745 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
23902746 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
2747
+ struct cifsFileInfo *wfile;
2748
+ struct cifs_tcon *tcon;
23912749 char *full_path = NULL;
23922750 int rc = -EACCES;
23932751 __u32 dosattr = 0;
....@@ -2395,7 +2753,7 @@
23952753
23962754 xid = get_xid();
23972755
2398
- cifs_dbg(FYI, "setattr on file %pd attrs->iavalid 0x%x\n",
2756
+ cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n",
23992757 direntry, attrs->ia_valid);
24002758
24012759 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
....@@ -2416,23 +2774,38 @@
24162774
24172775 /*
24182776 * Attempt to flush data before changing attributes. We need to do
2419
- * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
2420
- * ownership or mode then we may also need to do this. Here, we take
2421
- * the safe way out and just do the flush on all setattr requests. If
2422
- * the flush returns error, store it to report later and continue.
2777
+ * this for ATTR_SIZE and ATTR_MTIME. If the flush of the data
2778
+ * returns error, store it to report later and continue.
24232779 *
24242780 * BB: This should be smarter. Why bother flushing pages that
24252781 * will be truncated anyway? Also, should we error out here if
2426
- * the flush returns error?
2782
+ * the flush returns error? Do we need to check for ATTR_MTIME_SET flag?
24272783 */
2428
- rc = filemap_write_and_wait(inode->i_mapping);
2429
- if (is_interrupt_error(rc)) {
2430
- rc = -ERESTARTSYS;
2431
- goto cifs_setattr_exit;
2784
+ if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) {
2785
+ rc = filemap_write_and_wait(inode->i_mapping);
2786
+ if (is_interrupt_error(rc)) {
2787
+ rc = -ERESTARTSYS;
2788
+ goto cifs_setattr_exit;
2789
+ }
2790
+ mapping_set_error(inode->i_mapping, rc);
24322791 }
24332792
2434
- mapping_set_error(inode->i_mapping, rc);
24352793 rc = 0;
2794
+
2795
+ if ((attrs->ia_valid & ATTR_MTIME) &&
2796
+ !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
2797
+ rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
2798
+ if (!rc) {
2799
+ tcon = tlink_tcon(wfile->tlink);
2800
+ rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
2801
+ cifsFileInfo_put(wfile);
2802
+ if (rc)
2803
+ goto cifs_setattr_exit;
2804
+ } else if (rc != -EBADF)
2805
+ goto cifs_setattr_exit;
2806
+ else
2807
+ rc = 0;
2808
+ }
24362809
24372810 if (attrs->ia_valid & ATTR_SIZE) {
24382811 rc = cifs_set_file_size(inode, attrs, xid, full_path);
....@@ -2446,8 +2819,8 @@
24462819 if (attrs->ia_valid & ATTR_GID)
24472820 gid = attrs->ia_gid;
24482821
2449
-#ifdef CONFIG_CIFS_ACL
2450
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2822
+ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
2823
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
24512824 if (uid_valid(uid) || gid_valid(gid)) {
24522825 rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
24532826 uid, gid);
....@@ -2458,7 +2831,6 @@
24582831 }
24592832 }
24602833 } else
2461
-#endif /* CONFIG_CIFS_ACL */
24622834 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
24632835 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
24642836
....@@ -2469,8 +2841,8 @@
24692841 if (attrs->ia_valid & ATTR_MODE) {
24702842 mode = attrs->ia_mode;
24712843 rc = 0;
2472
-#ifdef CONFIG_CIFS_ACL
2473
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2844
+ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
2845
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
24742846 rc = id_mode_to_cifs_acl(inode, full_path, mode,
24752847 INVALID_UID, INVALID_GID);
24762848 if (rc) {
....@@ -2479,7 +2851,6 @@
24792851 goto cifs_setattr_exit;
24802852 }
24812853 } else
2482
-#endif /* CONFIG_CIFS_ACL */
24832854 if (((mode & S_IWUGO) == 0) &&
24842855 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
24852856