Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

cifs: add support for SEEK_DATA and SEEK_HOLE

Add llseek op for SEEK_DATA and SEEK_HOLE.
Improves xfstests/285,286,436,445,448 and 490

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Ronnie Sahlberg and committed by
Steve French
dece44e3 9ab70ca6

+99
+9
fs/cifs/cifsfs.c
··· 878 878 879 879 static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) 880 880 { 881 + struct cifsFileInfo *cfile = file->private_data; 882 + struct cifs_tcon *tcon; 883 + 881 884 /* 882 885 * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate 883 886 * the cached file length ··· 911 908 rc = cifs_revalidate_file_attr(file); 912 909 if (rc < 0) 913 910 return (loff_t)rc; 911 + } 912 + if (cfile && cfile->tlink) { 913 + tcon = tlink_tcon(cfile->tlink); 914 + if (tcon->ses->server->ops->llseek) 915 + return tcon->ses->server->ops->llseek(file, tcon, 916 + offset, whence); 914 917 } 915 918 return generic_file_llseek(file, offset, whence); 916 919 }
+2
fs/cifs/cifsglob.h
··· 497 497 /* version specific fiemap implementation */ 498 498 int (*fiemap)(struct cifs_tcon *tcon, struct cifsFileInfo *, 499 499 struct fiemap_extent_info *, u64, u64); 500 + /* version specific llseek implementation */ 501 + loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); 500 502 }; 501 503 502 504 struct smb_version_values {
+88
fs/cifs/smb2ops.c
··· 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) ··· 4250 4166 .ioctl_query_info = smb2_ioctl_query_info, 4251 4167 .make_node = smb2_make_node, 4252 4168 .fiemap = smb3_fiemap, 4169 + .llseek = smb3_llseek, 4253 4170 }; 4254 4171 4255 4172 struct smb_version_operations smb21_operations = { ··· 4351 4266 .ioctl_query_info = smb2_ioctl_query_info, 4352 4267 .make_node = smb2_make_node, 4353 4268 .fiemap = smb3_fiemap, 4269 + .llseek = smb3_llseek, 4354 4270 }; 4355 4271 4356 4272 struct smb_version_operations smb30_operations = { ··· 4461 4375 .ioctl_query_info = smb2_ioctl_query_info, 4462 4376 .make_node = smb2_make_node, 4463 4377 .fiemap = smb3_fiemap, 4378 + .llseek = smb3_llseek, 4464 4379 }; 4465 4380 4466 4381 struct smb_version_operations smb311_operations = { ··· 4572 4485 .ioctl_query_info = smb2_ioctl_query_info, 4573 4486 .make_node = smb2_make_node, 4574 4487 .fiemap = smb3_fiemap, 4488 + .llseek = smb3_llseek, 4575 4489 }; 4576 4490 4577 4491 struct smb_version_values smb20_values = {