Skip to content

Commit dece44e

Browse files
Ronnie Sahlbergsmfrench
authored andcommitted
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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 9ab70ca commit dece44e

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

fs/cifs/cifsfs.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,9 @@ static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
878878

879879
static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
880880
{
881+
struct cifsFileInfo *cfile = file->private_data;
882+
struct cifs_tcon *tcon;
883+
881884
/*
882885
* whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate
883886
* the cached file length
@@ -909,6 +912,12 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
909912
if (rc < 0)
910913
return (loff_t)rc;
911914
}
915+
if (cfile && cfile->tlink) {
916+
tcon = tlink_tcon(cfile->tlink);
917+
if (tcon->ses->server->ops->llseek)
918+
return tcon->ses->server->ops->llseek(file, tcon,
919+
offset, whence);
920+
}
912921
return generic_file_llseek(file, offset, whence);
913922
}
914923

fs/cifs/cifsglob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,8 @@ struct smb_version_operations {
497497
/* version specific fiemap implementation */
498498
int (*fiemap)(struct cifs_tcon *tcon, struct cifsFileInfo *,
499499
struct fiemap_extent_info *, u64, u64);
500+
/* version specific llseek implementation */
501+
loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int);
500502
};
501503

502504
struct smb_version_values {

fs/cifs/smb2ops.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,90 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
29222922
return rc;
29232923
}
29242924

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+
29253009
static int smb3_fiemap(struct cifs_tcon *tcon,
29263010
struct cifsFileInfo *cfile,
29273011
struct fiemap_extent_info *fei, u64 start, u64 len)
@@ -4166,6 +4250,7 @@ struct smb_version_operations smb20_operations = {
41664250
.ioctl_query_info = smb2_ioctl_query_info,
41674251
.make_node = smb2_make_node,
41684252
.fiemap = smb3_fiemap,
4253+
.llseek = smb3_llseek,
41694254
};
41704255

41714256
struct smb_version_operations smb21_operations = {
@@ -4266,6 +4351,7 @@ struct smb_version_operations smb21_operations = {
42664351
.ioctl_query_info = smb2_ioctl_query_info,
42674352
.make_node = smb2_make_node,
42684353
.fiemap = smb3_fiemap,
4354+
.llseek = smb3_llseek,
42694355
};
42704356

42714357
struct smb_version_operations smb30_operations = {
@@ -4375,6 +4461,7 @@ struct smb_version_operations smb30_operations = {
43754461
.ioctl_query_info = smb2_ioctl_query_info,
43764462
.make_node = smb2_make_node,
43774463
.fiemap = smb3_fiemap,
4464+
.llseek = smb3_llseek,
43784465
};
43794466

43804467
struct smb_version_operations smb311_operations = {
@@ -4485,6 +4572,7 @@ struct smb_version_operations smb311_operations = {
44854572
.ioctl_query_info = smb2_ioctl_query_info,
44864573
.make_node = smb2_make_node,
44874574
.fiemap = smb3_fiemap,
4575+
.llseek = smb3_llseek,
44884576
};
44894577

44904578
struct smb_version_values smb20_values = {

0 commit comments

Comments
 (0)