From: David Howells <dhowells@redhat.com>
To: Steve French <sfrench@samba.org>, Jeremy Allison <jra@samba.org>,
samba-technical@lists.samba.org
Cc: dhowells@redhat.com, linux-cifs@vger.kernel.org
Subject: Bug in Samba's implementation of FSCTL_QUERY_ALLOCATED_RANGES?
Date: Wed, 22 May 2024 00:53:59 +0100 [thread overview]
Message-ID: <349671.1716335639@warthog.procyon.org.uk> (raw)
I've been debugging a failure in xfstests generic/286 whereby llseek() return
-EIO and am thinking that the bug is in Samba. The test can be distilled to:
mount //my/share /mnt -ooptions
truncate -s 100M /mnt/a
for i in $(seq 0 5 100); do xfs_io -c "w ${i}M 1M" /mnt/a; done
xfstests-dev/src/seek_copy_test /mnt/a /mnt/b
This creates a big sparse file, makes 21 1MiB extents at 5MiB intervals and
then tries to copy them one at a time, using SEEK_DATA/SEEK_HOLE to enumerate
each extent.
I can see the error in the protocol being returned from the server:
16 2.353013398 192.168.6.2 → 192.168.6.1 SMB2 206 Ioctl Request FSCTL_QUERY_ALLOCATED_RANGES File: a
17 2.353220936 192.168.6.1 → 192.168.6.2 SMB2 143 Ioctl Response, Error: STATUS_BUFFER_TOO_SMALL
Stracing Samba shows:
lseek(30, 94371840, SEEK_HOLE) = 95420416
lseek(30, 95420416, SEEK_DATA) = 99614720
lseek(30, 99614720, SEEK_HOLE) = 100663296
lseek(30, 100663296, SEEK_DATA) = 104857600
lseek(30, 104857600, SEEK_HOLE) = 105906176
sendmsg(35, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0\0\0I", iov_len=4}, {iov_base=NULL, iov_len=0}, {iov_base="\376SMB@\0\1\0#\0\0\300\v\0\n\0\1\0\0\0\0\0\0\0\265\2\0\0\0\0\0\0"..., iov_len=64}, {iov_base="\t\0\0\0\0\0\0\0", iov_len=8}, {iov_base="\0", iov_len=1}], msg_iovlen=5, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT|MSG_NOSIGNAL) = 77
You can see the error code in the sendmsg() as "...#\0\0\300...".
Turning debugging on on Samba shows:
[2024/05/21 23:56:58.727547, 2] ../../source3/smbd/smb2_ioctl_filesys.c:707(fsctl_qar)
QAR output len 336 exceeds max 16
[2024/05/21 23:56:58.727652, 3] ../../source3/smbd/smb2_server.c:4031(smbd_smb2_request_error_ex)
smbd_smb2_request_error_ex: smbd_smb2_request_error_ex: idx[1] status[NT_STATUS_BUFFER_TOO_SMALL] || at ../../source3/smbd/smb2_ioctl.c:353
The "exceeds max 16" indicates the "Max Ioctl Out Size" setting passed in the
Ioctl Request frame (which can be seen as 16 in the full packet trace). 336
is 21 * 16.
This stems from the smb2_llseek() function in the cifs filesystem in the Linux
kernel calling:
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
FSCTL_QUERY_ALLOCATED_RANGES,
(char *)&in_data, sizeof(in_data),
sizeof(struct file_allocated_range_buffer),
(char **)&out_data, &out_data_len);
where the max_out_data_len parameter is sizeof() you can see, allowing for
just a single element to be returned. The file_allocated_range_buffer struct
is just:
struct file_allocated_range_buffer {
__le64 file_offset;
__le64 length;
} __packed;
which is 16 bytes - hence the maximum output data seen by Samba.
Now, cifs only wants the next extent. It fills in the input data with the
base file position and the EOF:
in_data.file_offset = cpu_to_le64(offset);
in_data.length = cpu_to_le64(i_size_read(inode));
and asks the server to retrieve the first allocated extent within this range.
In Samba, however, fsctl_qar() does not pass in_max_output to
fsctl_qar_seek_fill() and therefore doesn't limit the amount returned. The
fill loop seems only to be limited by the maximum file offset and not the max
buffer size.
The:
if (out_output->length > in_max_output) {
DEBUG(2, ("QAR output len %lu exceeds max %lu\n",
(unsigned long)out_output->length,
(unsigned long)in_max_output));
data_blob_free(out_output);
return NT_STATUS_BUFFER_TOO_SMALL;
}
check at the end of fsctl_qar() generates the complaint.
I think that fsctl_qar() should probably just discard the excess records.
Looking at:
https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-fsctl_query_allocated_ranges
it's not obvious what should be done if the available records won't fit.
Samba: samba-4.19.6-1.fc39.x86_64
Linux: 6.10 pre -rc1.
David
next reply other threads:[~2024-05-21 23:54 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-21 23:53 David Howells [this message]
2024-05-22 8:53 ` Bug in Samba's implementation of FSCTL_QUERY_ALLOCATED_RANGES? David Disseldorp
2024-05-22 10:36 ` David Howells
2024-05-23 4:54 ` David Disseldorp
2024-05-23 5:05 ` ronnie sahlberg
2024-05-23 6:21 ` David Howells
2024-05-23 6:28 ` ronnie sahlberg
2024-05-23 6:36 ` David Howells
2024-05-23 14:29 ` Tom Talpey
2024-05-23 15:28 ` Paulo Alcantara
2024-05-23 22:49 ` Jeremy Allison
2024-05-24 7:45 ` Stefan Metzmacher
2024-08-22 22:26 ` David Howells
2024-08-23 13:20 ` David Disseldorp
2024-08-28 10:25 ` David Howells
2024-08-28 10:55 ` David Disseldorp
2024-08-28 11:52 ` David Howells
2024-08-28 12:57 ` David Disseldorp
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=349671.1716335639@warthog.procyon.org.uk \
--to=dhowells@redhat.com \
--cc=jra@samba.org \
--cc=linux-cifs@vger.kernel.org \
--cc=samba-technical@lists.samba.org \
--cc=sfrench@samba.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox