From c4fd96016610171a31ad54a7883b3682680ef8d1 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Thu, 4 May 2017 14:55:43 +0200 Subject: [PATCH] vfs: add VFS_COPY_CHUNK_FL_IGNORE_LOCKS for dup extents MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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" 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 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 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 Reviewed-by: Ralph Böhme --- source3/include/vfs.h | 5 ++- source3/modules/vfs_btrfs.c | 50 +++++++++++++----------- source3/modules/vfs_default.c | 72 ++++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 55 deletions(-) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index fd493e4d03b..79089806e24 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -556,8 +556,11 @@ enum vfs_fallocate_flags { */ 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 { diff --git a/source3/modules/vfs_btrfs.c b/source3/modules/vfs_btrfs.c index 4be4ef632fe..e306ecec89f 100644 --- a/source3/modules/vfs_btrfs.c +++ b/source3/modules/vfs_btrfs.c @@ -154,27 +154,29 @@ static struct tevent_req *btrfs_copy_chunk_send(struct vfs_handle_struct *handle 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); @@ -184,8 +186,10 @@ static struct tevent_req *btrfs_copy_chunk_send(struct vfs_handle_struct *handle 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 diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index ffdc40ae87e..fa89f7f2551 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1605,6 +1605,7 @@ struct vfs_cc_state { off_t to_copy; off_t remaining; size_t next_io_size; + uint32_t flags; }; static NTSTATUS copy_chunk_loop(struct tevent_req *req); @@ -1650,6 +1651,7 @@ static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *hand .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)) { @@ -1704,18 +1706,20 @@ static NTSTATUS copy_chunk_loop(struct tevent_req *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, @@ -1743,10 +1747,12 @@ static void vfswrap_copy_chunk_read_done(struct tevent_req *subreq) 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); @@ -1764,19 +1770,21 @@ static void vfswrap_copy_chunk_read_done(struct tevent_req *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, @@ -1801,10 +1809,12 @@ static void vfswrap_copy_chunk_write_done(struct tevent_req *subreq) 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); -- 2.34.1