vfs: add VFS_COPY_CHUNK_FL_IGNORE_LOCKS for dup extents
authorDavid Disseldorp <ddiss@samba.org>
Thu, 4 May 2017 12:55:43 +0000 (14:55 +0200)
committerRalph Boehme <slow@samba.org>
Wed, 10 May 2017 06:22:19 +0000 (08:22 +0200)
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>
source3/include/vfs.h
source3/modules/vfs_btrfs.c
source3/modules/vfs_default.c

index fd493e4d03b4caf245e3e80ca9ad37a1ac428639..79089806e24d6f9f8987c163e79bc132999526f4 100644 (file)
@@ -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 {
index 4be4ef632fe1b2f4d0c3d6f656bc463eb2b7a89a..e306ecec89fc1813dae200edfd1e566a4d8edae2 100644 (file)
@@ -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
index ffdc40ae87e15adbc7cb3506b0b84ca6ba58c261..fa89f7f255147c2a9ace76ebbd90be02c4f9afac 100644 (file)
@@ -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);