As confirmed by the Microsoft Protocol Open Specifications Team: Windows
Server 2016 (ReFS) ignores locks for FSCTL_DUPLICATE_EXTENTS_TO_FILE...
From: Jeff McCashland
To: David Disseldorp
CC: "cifs-protocol@lists.samba.org" <cifs-protocol@lists.samba.org>
Subject: RE: [
116100414754619] FSCTL_DUPLICATE_EXTENTS_TO_FILE appears
to completely bypass file locks
Date: Mon, 12 Dec 2016 20:44:08 +0000
Hi David,
We have made the following spec changes for the next doc release:
In section 2.1.5.9.4 FSCTL_DUPLICATE_EXTENTS_TO_FILE behavior notes have
been added to the following paragraphs.
Before:
§ The object store MUST check for byte range lock conflicts on
Open.Stream using the algorithm described in section 2.1.4.10 with
ByteOffset set to InputBuffer.TargetFileOffset, Length set to
InputBuffer.ByteCount, IsExclusive set to TRUE, LockIntent set to FALSE,
and Open set to Open. If a conflict is detected, the operation MUST be
failed with STATUS_FILE_LOCK_CONFLICT.
§ The object store MUST check for byte range lock conflicts on Source
using the algorithm described in section 2.1.4.10 with ByteOffset set to
InputBuffer.SourceFileOffset, Length set to InputBuffer.ByteCount,
IsExclusive set to FALSE, LockIntent set to FALSE, and Open set to
InputBuffer.FileHandle. If a conflict is detected, the operation MUST be
failed with STATUS_FILE_LOCK_CONFLICT.
After:
§ The object store SHOULD<WBN1> check for byte range lock conflicts on
Open.Stream using the algorithm described in section 2.1.4.10 with
ByteOffset set to InputBuffer.TargetFileOffset, Length set to
InputBuffer.ByteCount, IsExclusive set to TRUE, LockIntent set to FALSE,
and Open set to Open. If a conflict is detected, the operation MUST be
failed with STATUS_FILE_LOCK_CONFLICT.
§ The object store SHOULD<WBN2> check for byte range lock conflicts on
Source using the algorithm described in section 2.1.4.10 with ByteOffset
set to InputBuffer.SourceFileOffset, Length set to
InputBuffer.ByteCount, IsExclusive set to FALSE, LockIntent set to
FALSE, and Open set to InputBuffer.FileHandle. If a conflict is
detected, the operation MUST be failed with STATUS_FILE_LOCK_CONFLICT.
WBN1: The ReFS file system in Windows Server 2016 does not check for
byte range lock conflicts on Open.Stream.
WBN2: The ReFS file system in Windows Server 2016 does not check for
byte range lock conflicts on Source.
Signed-off-by: David Disseldorp <ddiss@samba.org>
Reviewed-by: Ralph Böhme <slow@samba.org>
*/
enum vfs_copy_chunk_flags {
VFS_COPY_CHUNK_FL_MUST_CLONE = 0x0001,
+ VFS_COPY_CHUNK_FL_IGNORE_LOCKS = 0x0002,
- VFS_COPY_CHUNK_FL_MASK_ALL = 0x0001,
+ VFS_COPY_CHUNK_FL_MASK_ALL =
+ (VFS_COPY_CHUNK_FL_MUST_CLONE
+ | VFS_COPY_CHUNK_FL_IGNORE_LOCKS),
};
struct vfs_aio_state {
return tevent_req_post(req, ev);
}
- init_strict_lock_struct(src_fsp,
- src_fsp->op->global->open_persistent_id,
- src_off,
- num,
- READ_LOCK,
- &src_lck);
- init_strict_lock_struct(dest_fsp,
- dest_fsp->op->global->open_persistent_id,
- dest_off,
- num,
- WRITE_LOCK,
- &dest_lck);
-
- if (!SMB_VFS_STRICT_LOCK(src_fsp->conn, src_fsp, &src_lck)) {
- tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
- return tevent_req_post(req, ev);
- }
- if (!SMB_VFS_STRICT_LOCK(dest_fsp->conn, dest_fsp, &dest_lck)) {
- SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &src_lck);
- tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
- return tevent_req_post(req, ev);
+ if (!(flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ init_strict_lock_struct(src_fsp,
+ src_fsp->op->global->open_persistent_id,
+ src_off,
+ num,
+ READ_LOCK,
+ &src_lck);
+ init_strict_lock_struct(dest_fsp,
+ dest_fsp->op->global->open_persistent_id,
+ dest_off,
+ num,
+ WRITE_LOCK,
+ &dest_lck);
+
+ if (!SMB_VFS_STRICT_LOCK(src_fsp->conn, src_fsp, &src_lck)) {
+ tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
+ return tevent_req_post(req, ev);
+ }
+ if (!SMB_VFS_STRICT_LOCK(dest_fsp->conn, dest_fsp, &dest_lck)) {
+ SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &src_lck);
+ tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
+ return tevent_req_post(req, ev);
+ }
}
ZERO_STRUCT(cr_args);
cr_args.src_length = (uint64_t)num;
ret = ioctl(dest_fsp->fh->fd, BTRFS_IOC_CLONE_RANGE, &cr_args);
- SMB_VFS_STRICT_UNLOCK(dest_fsp->conn, dest_fsp, &dest_lck);
- SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &src_lck);
+ if (!(flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ SMB_VFS_STRICT_UNLOCK(dest_fsp->conn, dest_fsp, &dest_lck);
+ SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &src_lck);
+ }
if (ret < 0) {
/*
* BTRFS_IOC_CLONE_RANGE only supports 'sectorsize' aligned
off_t to_copy;
off_t remaining;
size_t next_io_size;
+ uint32_t flags;
};
static NTSTATUS copy_chunk_loop(struct tevent_req *req);
.dst_off = dest_off,
.to_copy = to_copy,
.remaining = to_copy,
+ .flags = flags,
};
state->buf = talloc_array(state, uint8_t, num);
if (tevent_req_nomem(state->buf, req)) {
state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
- init_strict_lock_struct(state->src_fsp,
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ init_strict_lock_struct(state->src_fsp,
state->src_fsp->op->global->open_persistent_id,
- state->src_off,
- state->next_io_size,
- READ_LOCK,
- &state->read_lck);
-
- ok = SMB_VFS_STRICT_LOCK(state->src_fsp->conn,
- state->src_fsp,
- &state->read_lck);
- if (!ok) {
- return NT_STATUS_FILE_LOCK_CONFLICT;
+ state->src_off,
+ state->next_io_size,
+ READ_LOCK,
+ &state->read_lck);
+
+ ok = SMB_VFS_STRICT_LOCK(state->src_fsp->conn,
+ state->src_fsp,
+ &state->read_lck);
+ if (!ok) {
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
}
subreq = SMB_VFS_PREAD_SEND(state,
ssize_t nread;
bool ok;
- SMB_VFS_STRICT_UNLOCK(state->src_fsp->conn,
- state->src_fsp,
- &state->read_lck);
- ZERO_STRUCT(state->read_lck);
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ SMB_VFS_STRICT_UNLOCK(state->src_fsp->conn,
+ state->src_fsp,
+ &state->read_lck);
+ ZERO_STRUCT(state->read_lck);
+ }
nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
TALLOC_FREE(subreq);
state->src_off += nread;
- init_strict_lock_struct(state->dst_fsp,
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ init_strict_lock_struct(state->dst_fsp,
state->dst_fsp->op->global->open_persistent_id,
- state->dst_off,
- state->next_io_size,
- WRITE_LOCK,
- &state->write_lck);
-
- ok = SMB_VFS_STRICT_LOCK(state->dst_fsp->conn,
- state->dst_fsp,
- &state->write_lck);
- if (!ok) {
- tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
- return;
+ state->dst_off,
+ state->next_io_size,
+ WRITE_LOCK,
+ &state->write_lck);
+
+ ok = SMB_VFS_STRICT_LOCK(state->dst_fsp->conn,
+ state->dst_fsp,
+ &state->write_lck);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
+ return;
+ }
}
subreq = SMB_VFS_PWRITE_SEND(state,
ssize_t nwritten;
NTSTATUS status;
- SMB_VFS_STRICT_UNLOCK(state->dst_fsp->conn,
- state->dst_fsp,
- &state->write_lck);
- ZERO_STRUCT(state->write_lck);
+ if (!(state->flags & VFS_COPY_CHUNK_FL_IGNORE_LOCKS)) {
+ SMB_VFS_STRICT_UNLOCK(state->dst_fsp->conn,
+ state->dst_fsp,
+ &state->write_lck);
+ ZERO_STRUCT(state->write_lck);
+ }
nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
TALLOC_FREE(subreq);