<div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-size:small;color:#000000"><span style="color:rgb(34,34,34)">On Thu, Aug 22, 2019 at 10:03 AM Niels de Vos &lt;<a href="mailto:ndevos@redhat.com">ndevos@redhat.com</a>&gt; wrote:</span><br></div></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Wed, Aug 21, 2019 at 07:04:17PM +0200, Max Reitz wrote:<br>
&gt; On 17.08.19 23:21, Nir Soffer wrote:<br>
&gt; &gt; Implement alignment probing similar to file-posix, by reading from the<br>
&gt; &gt; first 4k of the image.<br>
&gt; &gt; <br>
&gt; &gt; Before this change, provisioning a VM on storage with sector size of<br>
&gt; &gt; 4096 bytes would fail when the installer try to create filesystems. Here<br>
&gt; &gt; is an example command that reproduces this issue:<br>
&gt; &gt; <br>
&gt; &gt;     $ qemu-system-x86_64 -accel kvm -m 2048 -smp 2 \<br>
&gt; &gt;         -drive file=gluster://gluster1/gv0/fedora29.raw,format=raw,cache=none \<br>
&gt; &gt;         -cdrom Fedora-Server-dvd-x86_64-29-1.2.iso<br>
&gt; &gt; <br>
&gt; &gt; The installer fails in few seconds when trying to create filesystem on<br>
&gt; &gt; /dev/mapper/fedora-root. In error report we can see that it failed with<br>
&gt; &gt; EINVAL (I could not extract the error from guest).<br>
&gt; &gt; <br>
&gt; &gt; Copying disk fails with EINVAL:<br>
&gt; &gt; <br>
&gt; &gt;     $ qemu-img convert -p -f raw -O raw -t none -T none \<br>
&gt; &gt;         gluster://gluster1/gv0/fedora29.raw \<br>
&gt; &gt;         gluster://gluster1/gv0/fedora29-clone.raw<br>
&gt; &gt;     qemu-img: error while writing sector 4190208: Invalid argument<br>
&gt; &gt; <br>
&gt; &gt; This is a fix to same issue fixed in commit a6b257a08e3d (file-posix:<br>
&gt; &gt; Handle undetectable alignment) for gluster:// images.<br>
&gt; &gt; <br>
&gt; &gt; This fix has the same limit, that the first block of the image should be<br>
&gt; &gt; allocated, otherwise we cannot detect the alignment and fallback to a<br>
&gt; &gt; safe value (4096) even when using storage with sector size of 512 bytes.<br>
&gt; &gt; <br>
&gt; &gt; Signed-off-by: Nir Soffer &lt;<a href="mailto:nsoffer@redhat.com" target="_blank">nsoffer@redhat.com</a>&gt;<br>
&gt; &gt; ---<br>
&gt; &gt;  block/gluster.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++<br>
&gt; &gt;  1 file changed, 47 insertions(+)<br>
&gt; &gt; <br>
&gt; &gt; diff --git a/block/gluster.c b/block/gluster.c<br>
&gt; &gt; index f64dc5b01e..d936240b72 100644<br>
&gt; &gt; --- a/block/gluster.c<br>
&gt; &gt; +++ b/block/gluster.c<br>
&gt; &gt; @@ -52,6 +52,9 @@<br>
&gt; &gt;  <br>
&gt; &gt;  #define GERR_INDEX_HINT &quot;hint: check in &#39;server&#39; array index &#39;%d&#39;\n&quot;<br>
&gt; &gt;  <br>
&gt; &gt; +/* The value is known only on the server side. */<br>
&gt; &gt; +#define MAX_ALIGN 4096<br>
&gt; &gt; +<br>
&gt; &gt;  typedef struct GlusterAIOCB {<br>
&gt; &gt;      int64_t size;<br>
&gt; &gt;      int ret;<br>
&gt; &gt; @@ -902,8 +905,52 @@ out:<br>
&gt; &gt;      return ret;<br>
&gt; &gt;  }<br>
&gt; &gt;  <br>
&gt; &gt; +/*<br>
&gt; &gt; + * Check if read is allowed with given memory buffer and length.<br>
&gt; &gt; + *<br>
&gt; &gt; + * This function is used to check O_DIRECT request alignment.<br>
&gt; &gt; + */<br>
&gt; &gt; +static bool gluster_is_io_aligned(struct glfs_fd *fd, void *buf, size_t len)<br>
&gt; &gt; +{<br>
&gt; &gt; +    ssize_t ret = glfs_pread(fd, buf, len, 0, 0, NULL);<br>
&gt; &gt; +    return ret &gt;= 0 || errno != EINVAL;<br>
&gt; <br>
&gt; Is glfs_pread() guaranteed to return EINVAL on invalid alignment?<br>
&gt; file-posix says this is only the case on Linux (for normal files).  Now<br>
&gt; I also don’t know whether the gluster driver works on anything but Linux<br>
&gt; anyway.<br>
<br>
The behaviour depends on the filesystem used by the Gluster backend. XFS<br>
is the recommendation, but in the end it is up to the users. The Gluster<br>
server is known to work on Linux, NetBSD and FreeBSD, the vast majority<br>
of users runs it on Linux.<br>
<br>
I do not think there is a strong guarantee EINVAL is always correct. How<br>
about only checking &#39;ret &gt; 0&#39;?<br></blockquote><div><br></div><div><div class="gmail_default" style="font-size:small;color:rgb(0,0,0)">Looks like we don&#39;t have a choice.</div></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
&gt; <br>
&gt; &gt; +}<br>
&gt; &gt; +<br>
&gt; &gt; +static void gluster_probe_alignment(BlockDriverState *bs, struct glfs_fd *fd,<br>
&gt; &gt; +                                    Error **errp)<br>
&gt; &gt; +{<br>
&gt; &gt; +    char *buf;<br>
&gt; &gt; +    size_t alignments[] = {1, 512, 1024, 2048, 4096};<br>
&gt; &gt; +    size_t align;<br>
&gt; &gt; +    int i;<br>
&gt; &gt; +<br>
&gt; &gt; +    buf = qemu_memalign(MAX_ALIGN, MAX_ALIGN);<br>
&gt; &gt; +<br>
&gt; &gt; +    for (i = 0; i &lt; ARRAY_SIZE(alignments); i++) {<br>
&gt; &gt; +        align = alignments[i];<br>
&gt; &gt; +        if (gluster_is_io_aligned(fd, buf, align)) {<br>
&gt; &gt; +            /* Fallback to safe value. */<br>
&gt; &gt; +            bs-&gt;bl.request_alignment = (align != 1) ? align : MAX_ALIGN;<br>
&gt; &gt; +            break;<br>
&gt; &gt; +        }<br>
&gt; &gt; +    }<br>
&gt; <br>
&gt; I don’t like the fact that the last element of alignments[] should be<br>
&gt; the same as MAX_ALIGN, without that ever having been made explicit anywhere.<br>
&gt; <br>
&gt; It’s a bit worse in the file-posix patch, because if getpagesize() is<br>
&gt; greater than 4k, max_align will be greater than 4k.  But MAX_BLOCKSIZE<br>
&gt; is 4k, too, so I suppose we wouldn’t support any block size beyond that<br>
&gt; anyway, which makes the error message appropriate still.<br>
&gt; <br>
&gt; &gt; +<br>
&gt; &gt; +    qemu_vfree(buf);<br>
&gt; &gt; +<br>
&gt; &gt; +    if (!bs-&gt;bl.request_alignment) {<br>
&gt; &gt; +        error_setg(errp, &quot;Could not find working O_DIRECT alignment&quot;);<br>
&gt; &gt; +        error_append_hint(errp, &quot;Try cache.direct=off\n&quot;);<br>
&gt; &gt; +    }<br>
&gt; &gt; +}<br>
&gt; &gt; +<br>
&gt; &gt;  static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)<br>
&gt; &gt;  {<br>
&gt; &gt; +    BDRVGlusterState *s = bs-&gt;opaque;<br>
&gt; &gt; +<br>
&gt; &gt; +    gluster_probe_alignment(bs, s-&gt;fd, errp);<br>
&gt; &gt; +<br>
&gt; &gt; +    bs-&gt;bl.min_mem_alignment = bs-&gt;bl.request_alignment;<br>
&gt; <br>
&gt; Well, I’ll just trust you that there is no weird system where the memory<br>
&gt; alignment is greater than the request alignment.<br>
&gt; <br>
&gt; &gt; +    bs-&gt;bl.opt_mem_alignment = MAX(bs-&gt;bl.request_alignment, MAX_ALIGN);<br>
&gt; <br>
&gt; Isn’t request_alignment guaranteed to not exceed MAX_ALIGN, i.e. isn’t<br>
&gt; this always MAX_ALIGN?<br>
&gt; <br>
&gt; &gt;      bs-&gt;bl.max_transfer = GLUSTER_MAX_TRANSFER;<br>
&gt; &gt;  }<br>
&gt; <br>
&gt; file-posix has a check in raw_reopen_prepare() whether we can find a<br>
&gt; working alignment for the new FD.  Shouldn’t we do the same in<br>
&gt; qemu_gluster_reopen_prepare()?<br>
<br>
Yes, I think that makes sense too.<br></blockquote><div><br></div><div><div class="gmail_default" style="font-size:small;color:rgb(0,0,0)">I&#39;l add it in v2.</div><div class="gmail_default" style="font-size:small;color:rgb(0,0,0)"><br></div><div class="gmail_default" style="font-size:small;color:rgb(0,0,0)">Thanks for reviewing.</div></div><div class="gmail_default" style="font-size:small;color:rgb(0,0,0)"><br></div><div class="gmail_default" style="font-size:small;color:rgb(0,0,0)">Nir</div></div></div>