@@ -176,27 +176,27 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
176176 struct kvec * out_iov , int * out_buftype , struct dentry * dentry )
177177{
178178
179- struct reparse_data_buffer * rbuf ;
179+ struct smb2_query_info_rsp * qi_rsp = NULL ;
180180 struct smb2_compound_vars * vars = NULL ;
181- struct kvec * rsp_iov , * iov ;
182- struct smb_rqst * rqst ;
183- int rc ;
184- __le16 * utf16_path = NULL ;
185181 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
186- struct cifs_fid fid ;
182+ struct cifs_open_info_data * idata ;
187183 struct cifs_ses * ses = tcon -> ses ;
184+ struct reparse_data_buffer * rbuf ;
188185 struct TCP_Server_Info * server ;
189- int num_rqst = 0 , i ;
190186 int resp_buftype [MAX_COMPOUND ];
191- struct smb2_query_info_rsp * qi_rsp = NULL ;
192- struct cifs_open_info_data * idata ;
187+ int retries = 0 , cur_sleep = 1 ;
188+ __u8 delete_pending [8 ] = {1 ,};
189+ struct kvec * rsp_iov , * iov ;
193190 struct inode * inode = NULL ;
194- int flags = 0 ;
195- __u8 delete_pending [ 8 ] = { 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
191+ __le16 * utf16_path = NULL ;
192+ struct smb_rqst * rqst ;
196193 unsigned int size [2 ];
197- void * data [2 ];
194+ struct cifs_fid fid ;
195+ int num_rqst = 0 , i ;
198196 unsigned int len ;
199- int retries = 0 , cur_sleep = 1 ;
197+ int tmp_rc , rc ;
198+ int flags = 0 ;
199+ void * data [2 ];
200200
201201replay_again :
202202 /* reinitialize for possible replay */
@@ -639,7 +639,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
639639 tcon -> need_reconnect = true;
640640 }
641641
642+ tmp_rc = rc ;
642643 for (i = 0 ; i < num_cmds ; i ++ ) {
644+ char * buf = rsp_iov [i + i ].iov_base ;
645+
646+ if (buf && resp_buftype [i + 1 ] != CIFS_NO_BUFFER )
647+ rc = server -> ops -> map_error (buf , false);
648+ else
649+ rc = tmp_rc ;
643650 switch (cmds [i ]) {
644651 case SMB2_OP_QUERY_INFO :
645652 idata = in_iov [i ].iov_base ;
@@ -805,6 +812,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
805812 }
806813 }
807814 SMB2_close_free (& rqst [num_rqst ]);
815+ rc = tmp_rc ;
808816
809817 num_cmds += 2 ;
810818 if (out_iov && out_buftype ) {
@@ -860,22 +868,52 @@ static int parse_create_response(struct cifs_open_info_data *data,
860868 return rc ;
861869}
862870
871+ /* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */
872+ static bool ea_unsupported (int * cmds , int num_cmds ,
873+ struct kvec * out_iov , int * out_buftype )
874+ {
875+ int i ;
876+
877+ if (cmds [num_cmds - 1 ] != SMB2_OP_QUERY_WSL_EA )
878+ return false;
879+
880+ for (i = 1 ; i < num_cmds - 1 ; i ++ ) {
881+ struct smb2_hdr * hdr = out_iov [i ].iov_base ;
882+
883+ if (out_buftype [i ] == CIFS_NO_BUFFER || !hdr ||
884+ hdr -> Status != STATUS_SUCCESS )
885+ return false;
886+ }
887+ return true;
888+ }
889+
890+ static inline void free_rsp_iov (struct kvec * iovs , int * buftype , int count )
891+ {
892+ int i ;
893+
894+ for (i = 0 ; i < count ; i ++ ) {
895+ free_rsp_buf (buftype [i ], iovs [i ].iov_base );
896+ memset (& iovs [i ], 0 , sizeof (* iovs ));
897+ buftype [i ] = CIFS_NO_BUFFER ;
898+ }
899+ }
900+
863901int smb2_query_path_info (const unsigned int xid ,
864902 struct cifs_tcon * tcon ,
865903 struct cifs_sb_info * cifs_sb ,
866904 const char * full_path ,
867905 struct cifs_open_info_data * data )
868906{
907+ struct kvec in_iov [3 ], out_iov [5 ] = {};
908+ struct cached_fid * cfid = NULL ;
869909 struct cifs_open_parms oparms ;
870- __u32 create_options = 0 ;
871910 struct cifsFileInfo * cfile ;
872- struct cached_fid * cfid = NULL ;
911+ __u32 create_options = 0 ;
912+ int out_buftype [5 ] = {};
873913 struct smb2_hdr * hdr ;
874- struct kvec in_iov [3 ], out_iov [3 ] = {};
875- int out_buftype [3 ] = {};
914+ int num_cmds = 0 ;
876915 int cmds [3 ];
877916 bool islink ;
878- int i , num_cmds = 0 ;
879917 int rc , rc2 ;
880918
881919 data -> adjust_tz = false;
@@ -945,24 +983,33 @@ int smb2_query_path_info(const unsigned int xid,
945983 if (rc || !data -> reparse_point )
946984 goto out ;
947985
948- if (!tcon -> posix_extensions )
949- cmds [num_cmds ++ ] = SMB2_OP_QUERY_WSL_EA ;
950986 /*
951987 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
952988 * response.
953989 */
954990 if (data -> reparse .tag != IO_REPARSE_TAG_SYMLINK )
955991 cmds [num_cmds ++ ] = SMB2_OP_GET_REPARSE ;
992+ if (!tcon -> posix_extensions )
993+ cmds [num_cmds ++ ] = SMB2_OP_QUERY_WSL_EA ;
956994
957995 oparms = CIFS_OPARMS (cifs_sb , tcon , full_path ,
958996 FILE_READ_ATTRIBUTES |
959997 FILE_READ_EA | SYNCHRONIZE ,
960998 FILE_OPEN , create_options |
961999 OPEN_REPARSE_POINT , ACL_NO_MODE );
9621000 cifs_get_readable_path (tcon , full_path , & cfile );
1001+ free_rsp_iov (out_iov , out_buftype , ARRAY_SIZE (out_iov ));
9631002 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
9641003 & oparms , in_iov , cmds , num_cmds ,
965- cfile , NULL , NULL , NULL );
1004+ cfile , out_iov , out_buftype , NULL );
1005+ if (rc && ea_unsupported (cmds , num_cmds ,
1006+ out_iov , out_buftype )) {
1007+ if (data -> reparse .tag != IO_REPARSE_TAG_LX_BLK &&
1008+ data -> reparse .tag != IO_REPARSE_TAG_LX_CHR )
1009+ rc = 0 ;
1010+ else
1011+ rc = - EOPNOTSUPP ;
1012+ }
9661013 break ;
9671014 case - EREMOTE :
9681015 break ;
@@ -980,8 +1027,7 @@ int smb2_query_path_info(const unsigned int xid,
9801027 }
9811028
9821029out :
983- for (i = 0 ; i < ARRAY_SIZE (out_buftype ); i ++ )
984- free_rsp_buf (out_buftype [i ], out_iov [i ].iov_base );
1030+ free_rsp_iov (out_iov , out_buftype , ARRAY_SIZE (out_iov ));
9851031 return rc ;
9861032}
9871033
0 commit comments