@@ -2922,6 +2922,90 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
2922
2922
return rc ;
2923
2923
}
2924
2924
2925
+ static loff_t smb3_llseek (struct file * file , struct cifs_tcon * tcon , loff_t offset , int whence )
2926
+ {
2927
+ struct cifsFileInfo * wrcfile , * cfile = file -> private_data ;
2928
+ struct cifsInodeInfo * cifsi ;
2929
+ struct inode * inode ;
2930
+ int rc = 0 ;
2931
+ struct file_allocated_range_buffer in_data , * out_data = NULL ;
2932
+ u32 out_data_len ;
2933
+ unsigned int xid ;
2934
+
2935
+ if (whence != SEEK_HOLE && whence != SEEK_DATA )
2936
+ return generic_file_llseek (file , offset , whence );
2937
+
2938
+ inode = d_inode (cfile -> dentry );
2939
+ cifsi = CIFS_I (inode );
2940
+
2941
+ if (offset < 0 || offset >= i_size_read (inode ))
2942
+ return - ENXIO ;
2943
+
2944
+ xid = get_xid ();
2945
+ /*
2946
+ * We need to be sure that all dirty pages are written as they
2947
+ * might fill holes on the server.
2948
+ * Note that we also MUST flush any written pages since at least
2949
+ * some servers (Windows2016) will not reflect recent writes in
2950
+ * QUERY_ALLOCATED_RANGES until SMB2_flush is called.
2951
+ */
2952
+ wrcfile = find_writable_file (cifsi , false);
2953
+ if (wrcfile ) {
2954
+ filemap_write_and_wait (inode -> i_mapping );
2955
+ smb2_flush_file (xid , tcon , & wrcfile -> fid );
2956
+ cifsFileInfo_put (wrcfile );
2957
+ }
2958
+
2959
+ if (!(cifsi -> cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE )) {
2960
+ if (whence == SEEK_HOLE )
2961
+ offset = i_size_read (inode );
2962
+ goto lseek_exit ;
2963
+ }
2964
+
2965
+ in_data .file_offset = cpu_to_le64 (offset );
2966
+ in_data .length = cpu_to_le64 (i_size_read (inode ));
2967
+
2968
+ rc = SMB2_ioctl (xid , tcon , cfile -> fid .persistent_fid ,
2969
+ cfile -> fid .volatile_fid ,
2970
+ FSCTL_QUERY_ALLOCATED_RANGES , true,
2971
+ (char * )& in_data , sizeof (in_data ),
2972
+ sizeof (struct file_allocated_range_buffer ),
2973
+ (char * * )& out_data , & out_data_len );
2974
+ if (rc == - E2BIG )
2975
+ rc = 0 ;
2976
+ if (rc )
2977
+ goto lseek_exit ;
2978
+
2979
+ if (whence == SEEK_HOLE && out_data_len == 0 )
2980
+ goto lseek_exit ;
2981
+
2982
+ if (whence == SEEK_DATA && out_data_len == 0 ) {
2983
+ rc = - ENXIO ;
2984
+ goto lseek_exit ;
2985
+ }
2986
+
2987
+ if (out_data_len < sizeof (struct file_allocated_range_buffer )) {
2988
+ rc = - EINVAL ;
2989
+ goto lseek_exit ;
2990
+ }
2991
+ if (whence == SEEK_DATA ) {
2992
+ offset = le64_to_cpu (out_data -> file_offset );
2993
+ goto lseek_exit ;
2994
+ }
2995
+ if (offset < le64_to_cpu (out_data -> file_offset ))
2996
+ goto lseek_exit ;
2997
+
2998
+ offset = le64_to_cpu (out_data -> file_offset ) + le64_to_cpu (out_data -> length );
2999
+
3000
+ lseek_exit :
3001
+ free_xid (xid );
3002
+ kfree (out_data );
3003
+ if (!rc )
3004
+ return vfs_setpos (file , offset , inode -> i_sb -> s_maxbytes );
3005
+ else
3006
+ return rc ;
3007
+ }
3008
+
2925
3009
static int smb3_fiemap (struct cifs_tcon * tcon ,
2926
3010
struct cifsFileInfo * cfile ,
2927
3011
struct fiemap_extent_info * fei , u64 start , u64 len )
@@ -4166,6 +4250,7 @@ struct smb_version_operations smb20_operations = {
4166
4250
.ioctl_query_info = smb2_ioctl_query_info ,
4167
4251
.make_node = smb2_make_node ,
4168
4252
.fiemap = smb3_fiemap ,
4253
+ .llseek = smb3_llseek ,
4169
4254
};
4170
4255
4171
4256
struct smb_version_operations smb21_operations = {
@@ -4266,6 +4351,7 @@ struct smb_version_operations smb21_operations = {
4266
4351
.ioctl_query_info = smb2_ioctl_query_info ,
4267
4352
.make_node = smb2_make_node ,
4268
4353
.fiemap = smb3_fiemap ,
4354
+ .llseek = smb3_llseek ,
4269
4355
};
4270
4356
4271
4357
struct smb_version_operations smb30_operations = {
@@ -4375,6 +4461,7 @@ struct smb_version_operations smb30_operations = {
4375
4461
.ioctl_query_info = smb2_ioctl_query_info ,
4376
4462
.make_node = smb2_make_node ,
4377
4463
.fiemap = smb3_fiemap ,
4464
+ .llseek = smb3_llseek ,
4378
4465
};
4379
4466
4380
4467
struct smb_version_operations smb311_operations = {
@@ -4485,6 +4572,7 @@ struct smb_version_operations smb311_operations = {
4485
4572
.ioctl_query_info = smb2_ioctl_query_info ,
4486
4573
.make_node = smb2_make_node ,
4487
4574
.fiemap = smb3_fiemap ,
4575
+ .llseek = smb3_llseek ,
4488
4576
};
4489
4577
4490
4578
struct smb_version_values smb20_values = {
0 commit comments