Lseek
From Linux NFS
SEEK is an operation that allows a client to determine the location of the next data_content4 in a file. It allows an implementation of the emerging extension to lseek(2) to allow clients to determine SEEK_HOLE and SEEK_DATA.
Contents |
Data type reference
typedef uint64_t length4
typedef uint64_t offset4
enum data_content4 {
NFS4_CONTENT_DATA = 0,
NFS4_CONTENT_APP_DATA_HOLE = 1,
NFS4_CONTENT_HOLE = 2,
};
struct data_info4 {
offset4 di_offset;
length4 di_length;
bool di_allocated;
};
Argument
struct SEEK4args {
/* CURRENT_FH: file */
stateid4 sa_stateid;
offset4 sa_offset;
data_content4 sa_what;
};
Result
union seek_content switch (data_content4 content) {
case NFS4_CONTENT_DATA:
data_info4 sc_data;
case NFS4_CONTENT_APP_DATA_HOLE:
app_data_hole4 sc_adh;
case NFS4_CONTENT_HOLE:
data_info4 sc_hole;
default:
void;
};
struct seek_res4 {
bool sr_eof;
seek_content sr_contents;
};
union SEEK4res switch (nfsstat4 status) {
case NFS4_OK:
seek_res4 resok4;
default:
void;
};
Client
- Continue to use nfs_file_llseek() in fs/nfs/file.c for NFS v2, v3, v4.0 and v4.1.
- Need to optimize for SEEK_SET, SEEK_CUR and SEEK_END cases (fall back to the VFS). I think this should be enough:
case SEEK_HOLE:
case SEEK_DATA:
return nfs42_file_llseek();
break;
default:
return nfs_file_llseek();
- Use the compound:
SEQUENCE
PUTFH
SEEK
- Flush the file to disk (nfs_wb_all) before attempting to seek that way the server knows where to find data.
- Send either NFS4_CONTENT_DATA xor NFS4_CONTENT_HOLE but not the NFS4_CONTENT_APP_DATA_HOLE option.
- Decode the data_info4 to find the di_offset and call vfs_setpos() with that value.
- Return -ENXIO if the server has sr_eof set, indicating an out-of-bounds seek.
Server
- Need to call preprocess_stateid_op() for both RD_STATE and WR_STATE. Is there a better way to do this?
- If sa_what == NFS4_CONTENT_DATA:
- di_offset = vfs_llseek(sa_offset, SEEK_DATA)
- di_length = vfs_llseek(di_offset, SEEK_HOLE) - di_offset
- If sa_what == NFS4_CONTENT_HOLE:
- di_offset = vfs_llseek(sa_offset, SEEK_HOLE)
- di_length = vfs_llseek(di_offset, SEEK_DATA) - di_offset
- Set sr_eof to true if di_offset == -ENXIO is returned and zero out the data_info4 fields in the result.
- I don't know how to find the value of di_allocated.
Testing
xfs tests #285 and #286 both test allocating files and punching holes through use of the lseek() function. They can be used for testing SEEK_HOLE and SEEK_DATA implementation.
Status
- Both client and server code has been written.
- Tests 7, 8, and 9 of xfstests generic/258 use fallocate() to punch holes and are therefore not running yet.
- Test 11 and 12 of generic/258 test huge files and currently have failing sub-tests, but the error is being generated by the vfs on the server.