Lseek

From Linux NFS

(Redirected from SEEK HOLE and SEEK DATA)
Jump to: navigation, search

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.
Personal tools