Subject: [nfsv4] Some XDR for SEEK

From: Thomas Haynes <[email-masked]>
Date: Sun, 25 Sep 2011 16:13:22 -0500

We don't need both SEEK_HOLE and SEEK_DATA, so I went with SEEK:

struct data_info4 {
        offset4         di_offset;
        length4         di_length;
        bool            di_allocated;
};

struct READ_PLUS4args {
        /* CURRENT_FH: file */
        stateid4        rpa_stateid;
        offset4         rpa_offset;
        count4          rpa_count;
};

union read_plus_content switch (data_content4 content) {
case NFS4_CONTENT_DATA:
        opaque          rpc_data<>;
case NFS4_CONTENT_APP_BLOCK:
        app_data_block4 rpc_block;
case NFS4_CONTENT_HOLE:
        data_info4      rpc_hole;
default:
        void;
};

/*
 * Allow a return of an array of contents.
 */
struct read_plus_res4 {
        bool                    rpr_eof;
        read_plus_content       rpr_contents<>;
};

union READ_PLUS4res switch (nfsstat4 status) {
case NFS4_OK:
        read_plus_res4  resok4;
default:
        void;
};
struct SEEK4args {
        /* CURRENT_FH: file */
        stateid4        sa_stateid;
        offset4         sa_offset;
        count4          sa_count;
};

union seek_content switch (data_content4 content) {
case NFS4_CONTENT_DATA:
        data_info4      sc_data;
case NFS4_CONTENT_APP_BLOCK:
        app_data_block4 sc_block;
case NFS4_CONTENT_HOLE:
        data_info4      sc_hole;
default:
        void;
};

/*
 * Allow a return of an array of contents.
 */
struct seek_res4 {
        bool            sr_eof;
        seek_content    sr_contents<>;
};

union SEEK4res switch (nfsstat4 status) {
case NFS4_OK:
        seek_res4       resok4;
default:
        void;
};

As can be seen, I've moved hole_info4 to be data_info4, it describes information about a range of data.

In the case of READ_PLUS, it is used to describe holes. In the case of SEEK, it is used to describe both
holes and data. I.e., with a SEEK, we do not want to actually return the data, just information about
where it ends.

I've also added di_allocated, which tells us whether a hole is unallocated blocks or a block of data
which is zeroed and can be sent back as a hole.

With SEEK, you could conceivably ask for the entire file - this is because like REA_PLUS it returns
an array of data, hole, and adbs.

Note to follow hole semantics, it has to return both the start and end of each entry.

If the file has 4k blocks and the first 32k is a hole, the next 16k is data, and the last 16k is a hole, then
a SEEK at 20k for a range of 2k must return a data entry starting at 32k and ending at 48k. For SEEK,
sa_count is where to stop searching, not where to stop reporting.

If a file has 1G of data and no holes, then any SEEK inside it must return a single result of EOF and
data with 0 as the start and 1G as the end.

Contrast this a 2G file which has 1G of data and then a hole. A SEEK anywhere within the first G
and not going out of it, must return a result of not EOF and data with 0 as the start and 1G as the
end.

Another example would be a 72k file which some application has filled with zeros. I.e., it is allocated.
The server can report this either as data or as an allocated hole.

Finally, another semantic now occurs that say a file has 32k of allocated zeros followed by 32k of
unallocated zeros. If an application either does a READ_PLUS or a SEEK for 64k, it must get back
an array of two entries:

Either:

a)
0 -> 32k-1 :  hole (allocated)
32k -> 64k-1 : hole (unallocated)

b)
0 -> 32k-1 :  data
32k -> 64k-1 : hole (unallocated)

Both answers are acceptable, whilst the following is not:

0 -> 64k-1 :  hole (allocated | unallocated)

---

From: Trond Myklebust <[email-masked]>
Date: Mon, 26 Sep 2011 16:52:05 -0400

> We don't need both SEEK_HOLE and SEEK_DATA, so I went with SEEK:
<snip> 
>         count4          sa_count;

Why does SEEK need a 'sa_count' argument? That's useful if you want to
map a section of the file into data/hole/app block, but less so if you
just want to find the end of the current data/hole/app block section
(which is what seek(SEEK_HOLE/SEEK_DATA) would do).

Cheers
  Trond 
-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
[email-masked]
www.netapp.com

---

From: Thomas Haynes <[email-masked]>
Date: Mon, 26 Sep 2011 16:15:41 -0500

> (which is what seek(SEEK_HOLE/SEEK_DATA) would do).

Yeah, mapping a section and code reuse. Other than that, no reason.

---

From: Thomas Haynes <[email-masked]>
Date: Mon, 26 Sep 2011 16:23:46 -0500

> Yeah, mapping a section and code reuse. Other than that, no reason.

Well actually, there was an explicit reason - a goal to make this look
as much like READ_PLUS without actually returning the data.

I.e., this doesn't map directly onto SEEK_HOLE and SEEK_DATA,
but is a bit more flexible. It can for example generate a space
map in one call.

---

From: Trond Myklebust <[email-masked]>
Date: Mon, 26 Sep 2011 18:07:12 -0400

> but is a bit more flexible. It can for example generate a space

Yes, but it requires the client to estimate the size of the hole/data in
the seek() case. Otherwise, the server is liable to return too much or
too little data.

IOW: I'm fine with having options to generate space maps should there be
a demand for it, but it would be useful to also have equivalents of
'find the next', since that is what will be implemented in clients.

Cheers
  Trond

NetApp

---

From: Thomas Haynes <[email-masked]>
Date: Mon, 26 Sep 2011 17:11:04 -0500

> 'find the next', since that is what will be implemented in clients.

SEEK 4k, 1

States to find the next boundary at offset 4k.