pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Implement |FSCTL_DUPLICATE_EXTENTS_TO_FILE| vai NFSV4.2 CLONE+misc, 2025-04-15
Posted by Anonymous on Tue 15th Apr 2025 17:52
raw | new post

  1. From da8ec06b4731a97db63b5ba4d4983a3ef9797365 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Mon, 14 Apr 2025 17:07:42 +0200
  4. Subject: [PATCH 1/4] tests: Directory for TMPDIR/TMP/TEMP should be created
  5.  with chmod a+rwxt
  6.  
  7. Directory for TMPDIR/TMP/TEMP should be created with chmod a+rwxt
  8.  
  9. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  10. ---
  11. tests/manual_testing.txt              | 2 +-
  12.  tests/nfsbuildtest/nfsbuildtest.ksh93 | 3 +++
  13.  2 files changed, 4 insertions(+), 1 deletion(-)
  14.  
  15. diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
  16. index ed124ff..4da80fe 100644
  17. --- a/tests/manual_testing.txt
  18. +++ b/tests/manual_testing.txt
  19. @@ -461,7 +461,7 @@ $ bash -c 'cd -@ "x1" && ls -la'
  20.  #
  21.  One-liner, should print two times lines with "test OK", stderr should be empty
  22.  ---- snip ----
  23. -$ time ksh93 -c 'rm -Rf nfstmp1 gcc.x.strace.log x.c x.exe && mkdir nfstmp1 ; export TMPDIR="$PWD/nfstmp1" TEMP="$PWD/nfstmp1" TMP="$PWD/nfstmp1"; rm -f x.c x.exe && printf "#include <stdio.h>\n#include <stdlib.h>\nint main(int ac, char *av[]) { puts(\"hello world\"); return EXIT_SUCCESS;}\n" >x.c && strace -b $((512*1024)) -m syscall -o gcc.x.strace.log gcc x.c -o x.exe && ./x.exe && echo "# Compile Test OK" ; n="$(grep -E "/nfstmp1/.+\.o" gcc.x.strace.log | wc -l)" ; if (( n > 0 )) ; then echo "# Temp usage test OK: used by *.o files" ; else echo "# Test *.o FAILED" ; fi'
  24. +$ time ksh93 -c 'rm -Rf nfstmp1 gcc.x.strace.log x.c x.exe && mkdir nfstmp1 && chmod a+rwxt nfstmp1 ; export TMPDIR="$PWD/nfstmp1" TEMP="$PWD/nfstmp1" TMP="$PWD/nfstmp1"; rm -f x.c x.exe && printf "#include <stdio.h>\n#include <stdlib.h>\nint main(int ac, char *av[]) { puts(\"hello world\"); return EXIT_SUCCESS;}\n" >x.c && strace -b $((512*1024)) -m syscall -o gcc.x.strace.log gcc x.c -o x.exe && ./x.exe && echo "# Compile Test OK" ; n="$(grep -E "/nfstmp1/.+\.o" gcc.x.strace.log | wc -l)" ; if (( n > 0 )) ; then echo "# Temp usage test OK: used by *.o files" ; else echo "# Test *.o FAILED" ; fi'
  25.  ---- snip ---
  26.  
  27.  #
  28. diff --git a/tests/nfsbuildtest/nfsbuildtest.ksh93 b/tests/nfsbuildtest/nfsbuildtest.ksh93
  29. index a12967d..ac5726e 100644
  30. --- a/tests/nfsbuildtest/nfsbuildtest.ksh93
  31. +++ b/tests/nfsbuildtest/nfsbuildtest.ksh93
  32. @@ -79,6 +79,7 @@ function gcc_build
  33.  
  34.         tmpdir="$PWD/tmpdir"
  35.         mkdir -p "$tmpdir"
  36. +       chmod a+rwxt "$tmpdir"
  37.         if [[ -d "$tmpdir" && -w "$tmpdir" ]] ; then
  38.                 printf '#### Using temp dir %q\n' "$tmpdir"
  39.                 export TMPDIR="$tmpdir"
  40. @@ -255,6 +256,7 @@ function bash_build
  41.  
  42.         tmpdir="$PWD/tmpdir"
  43.         mkdir -p "$tmpdir"
  44. +       chmod a+rwxt "$tmpdir"
  45.         if [[ -d "$tmpdir" && -w "$tmpdir" ]] ; then
  46.                 printf '#### Using temp dir %q\n' "$tmpdir"
  47.                 export TMPDIR="$tmpdir"
  48. @@ -423,6 +425,7 @@ function msnfs41client_build
  49.  
  50.         tmpdir="$PWD/tmpdir"
  51.         mkdir -p "$tmpdir"
  52. +       chmod a+rwxt "$tmpdir"
  53.         if [[ -d "$tmpdir" && -w "$tmpdir" ]] ; then
  54.                 printf '#### Using temp dir %q\n' "$tmpdir"
  55.                 export TMPDIR="$tmpdir"
  56. --
  57. 2.45.1
  58.  
  59. From 61fc10a93aef4d556b0eebad4b24c17bec1d2676 Mon Sep 17 00:00:00 2001
  60. From: Roland Mainz <roland.mainz@nrubsig.org>
  61. Date: Mon, 14 Apr 2025 18:02:39 +0200
  62. Subject: [PATCH 2/4] daemon: |get_superblock_attrs()| debug output should log
  63.  |sparse_file_support|
  64.  
  65. |get_superblock_attrs()| debug output should log |sparse_file_support|
  66.  
  67. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  68. ---
  69. daemon/nfs41_superblock.c | 5 +++--
  70.  1 file changed, 3 insertions(+), 2 deletions(-)
  71.  
  72. diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
  73. index db75c09..880b115 100644
  74. --- a/daemon/nfs41_superblock.c
  75. +++ b/daemon/nfs41_superblock.c
  76. @@ -154,14 +154,15 @@ static int get_superblock_attrs(
  77.          "maxread=%llu, maxwrite=%llu, layout_types: 0x%X, "
  78.          "cansettime=%u, time_delta={%llu,%u}, aclsupport=%u, "
  79.          "link_support=%u, symlink_support=%u, case_preserving=%u, "
  80. -        "case_insensitive=%u\n",
  81. +        "case_insensitive=%u sparse_file_support=%u\n",
  82.          superblock->fsid.major, superblock->fsid.minor,
  83.          superblock->maxread, superblock->maxwrite,
  84.          superblock->layout_types, superblock->cansettime,
  85.          superblock->time_delta.seconds, superblock->time_delta.nseconds,
  86.          superblock->aclsupport, superblock->link_support,
  87.          superblock->symlink_support, superblock->case_preserving,
  88. -        superblock->case_insensitive));
  89. +        superblock->case_insensitive,
  90. +        superblock->sparse_file_support));
  91.  out:
  92.      return status;
  93.  }
  94. --
  95. 2.45.1
  96.  
  97. From 6db298479fb8b151926d9cd7d8a425fb7ee705ec Mon Sep 17 00:00:00 2001
  98. From: Roland Mainz <roland.mainz@nrubsig.org>
  99. Date: Tue, 15 Apr 2025 15:38:19 +0200
  100. Subject: [PATCH 3/4] daemon,include,sys: Add upcall/downcall for
  101.  |NFS41_SYSOP_FSCTL_DUPLICATE_DATA|
  102.  
  103. Add upcall/downcall for |NFS41_SYSOP_FSCTL_DUPLICATE_DATA|
  104.  
  105. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  106. ---
  107. daemon/daemon_debug.c     |   1 +
  108.  daemon/fsctl.c            |  83 +++++++++++++
  109.  daemon/nfs41.h            |   1 +
  110.  daemon/nfs41_superblock.c |  14 ++-
  111.  daemon/upcall.c           |   2 +
  112.  daemon/upcall.h           |   8 ++
  113.  include/nfs41_driver.h    |   1 +
  114.  sys/nfs41sys_debug.c      |   1 +
  115.  sys/nfs41sys_driver.h     |  14 +++
  116.  sys/nfs41sys_fsctl.c      | 248 ++++++++++++++++++++++++++++++++++++++
  117.  sys/nfs41sys_updowncall.c |   7 ++
  118.  11 files changed, 378 insertions(+), 2 deletions(-)
  119.  
  120. diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
  121. index 50856e9..10fd4b9 100644
  122. --- a/daemon/daemon_debug.c
  123. +++ b/daemon/daemon_debug.c
  124. @@ -468,6 +468,7 @@ const char* opcode2string(nfs41_opcodes opcode)
  125.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_ACL_SET)
  126.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES)
  127.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_SET_ZERO_DATA)
  128. +        NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_DUPLICATE_DATA)
  129.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_INVALID_OPCODE1)
  130.          default: break;
  131.      }
  132. diff --git a/daemon/fsctl.c b/daemon/fsctl.c
  133. index 87937cc..fa0c342 100644
  134. --- a/daemon/fsctl.c
  135. +++ b/daemon/fsctl.c
  136. @@ -29,6 +29,7 @@
  137.  
  138.  #define QARLVL 2 /* dprintf level for "query allocated ranges" logging */
  139.  #define SZDLVL 2 /* dprintf level for "set zero data" logging */
  140. +#define DDLVL  0 /* dprintf level for "duplicate data" logging */
  141.  
  142.  static int parse_queryallocatedranges(unsigned char *buffer,
  143.      uint32_t length, nfs41_upcall *upcall)
  144. @@ -429,3 +430,85 @@ const nfs41_upcall_op nfs41_op_setzerodata = {
  145.      .marshall = marshall_setzerodata,
  146.      .arg_size = sizeof(setzerodata_upcall_args)
  147.  };
  148. +
  149. +static int parse_duplicatedata(unsigned char *buffer,
  150. +    uint32_t length, nfs41_upcall *upcall)
  151. +{
  152. +    int status;
  153. +    duplicatedata_upcall_args *args = &upcall->args.duplicatedata;
  154. +
  155. +    status = safe_read(&buffer, &length, &args->src_state,
  156. +        sizeof(args->src_state));
  157. +    if (status) goto out;
  158. +    status = safe_read(&buffer, &length, &args->srcfileoffset,
  159. +        sizeof(args->srcfileoffset));
  160. +    if (status) goto out;
  161. +    status = safe_read(&buffer, &length, &args->destfileoffset,
  162. +        sizeof(args->destfileoffset));
  163. +    if (status) goto out;
  164. +    status = safe_read(&buffer, &length, &args->bytecount,
  165. +        sizeof(args->bytecount));
  166. +    if (status) goto out;
  167. +
  168. +    DPRINTF(DDLVL, ("parse_duplicatedata: "
  169. +        "parsing '%s' "
  170. +        "duplicatedata=(src_state=0x%p srcfileoffset=%lld "
  171. +        "destfileoffset=%lld bytecount=%lld)\n",
  172. +        opcode2string(upcall->opcode),
  173. +        (long long)args->src_state,
  174. +        (long long)args->srcfileoffset,
  175. +        (long long)args->destfileoffset,
  176. +        (long long)args->bytecount));
  177. +out:
  178. +    return status;
  179. +}
  180. +
  181. +static
  182. +int handle_duplicatedata(void *daemon_context,
  183. +    nfs41_upcall *upcall)
  184. +{
  185. +    int status = ERROR_INVALID_PARAMETER;
  186. +    duplicatedata_upcall_args *args = &upcall->args.duplicatedata;
  187. +    nfs41_open_state *state = upcall->state_ref;
  188. +//    nfs41_session *session = state->session;
  189. +//    nfs41_path_fh *file = &state->file;
  190. +
  191. +    DPRINTF(DDLVL,
  192. +        ("--> handle_duplicatedata("
  193. +            "state->path.path='%s', "
  194. +            "src_state->path.path='%s')\n",
  195. +            state->path.path,
  196. +            args->src_state->path.path));
  197. +
  198. +    /* NFS CLONE requires NFSv4.2 */
  199. +    if (state->session->client->root->nfsminorvers < 2) {
  200. +        status = ERROR_NOT_SUPPORTED;
  201. +        goto out;
  202. +    }
  203. +
  204. +    /* FIXME: Cloning not implemented yet */
  205. +    status = ERROR_NOT_SUPPORTED;
  206. +
  207. +out:
  208. +    DPRINTF(0,
  209. +        ("<-- handle_duplicatedata(), status=0x%lx\n",
  210. +        status));
  211. +
  212. +    return status;
  213. +}
  214. +
  215. +static int marshall_duplicatedata(unsigned char *buffer,
  216. +    uint32_t *length, nfs41_upcall *upcall)
  217. +{
  218. +    setzerodata_upcall_args *args = &upcall->args.setzerodata;
  219. +    int status;
  220. +    status = safe_write(&buffer, length, &args->ctime, sizeof(args->ctime));
  221. +    return status;
  222. +}
  223. +
  224. +const nfs41_upcall_op nfs41_op_duplicatedata = {
  225. +    .parse = parse_duplicatedata,
  226. +    .handle = handle_duplicatedata,
  227. +    .marshall = marshall_duplicatedata,
  228. +    .arg_size = sizeof(duplicatedata_upcall_args)
  229. +};
  230. diff --git a/daemon/nfs41.h b/daemon/nfs41.h
  231. index 7805659..9c2bdab 100644
  232. --- a/daemon/nfs41.h
  233. +++ b/daemon/nfs41.h
  234. @@ -59,6 +59,7 @@ typedef struct __nfs41_superblock {
  235.      unsigned int case_preserving : 1;
  236.      unsigned int case_insensitive : 1;
  237.      unsigned int sparse_file_support : 1;
  238. +    unsigned int block_clone_support : 1;
  239.  
  240.      /* variable filesystem attributes */
  241.      uint64_t space_avail;
  242. diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
  243. index 880b115..c64f129 100644
  244. --- a/daemon/nfs41_superblock.c
  245. +++ b/daemon/nfs41_superblock.c
  246. @@ -125,6 +125,12 @@ static int get_superblock_attrs(
  247.      superblock->case_preserving = info.case_preserving;
  248.      superblock->case_insensitive = info.case_insensitive;
  249.      superblock->sparse_file_support = 1; /* always ON for now */
  250. +    if (session->client->root->nfsminorvers >= 2) {
  251. +        superblock->block_clone_support = 1;
  252. +    }
  253. +    else {
  254. +        superblock->block_clone_support = 0;
  255. +    }
  256.  
  257.      if (bitmap_isset(&info.attrmask, 0, FATTR4_WORD0_CANSETTIME))
  258.          superblock->cansettime = info.cansettime;
  259. @@ -154,7 +160,8 @@ static int get_superblock_attrs(
  260.          "maxread=%llu, maxwrite=%llu, layout_types: 0x%X, "
  261.          "cansettime=%u, time_delta={%llu,%u}, aclsupport=%u, "
  262.          "link_support=%u, symlink_support=%u, case_preserving=%u, "
  263. -        "case_insensitive=%u sparse_file_support=%u\n",
  264. +        "case_insensitive=%u, sparse_file_support=%u, "
  265. +        "block_clone_support=%u\n",
  266.          superblock->fsid.major, superblock->fsid.minor,
  267.          superblock->maxread, superblock->maxwrite,
  268.          superblock->layout_types, superblock->cansettime,
  269. @@ -162,7 +169,8 @@ static int get_superblock_attrs(
  270.          superblock->aclsupport, superblock->link_support,
  271.          superblock->symlink_support, superblock->case_preserving,
  272.          superblock->case_insensitive,
  273. -        superblock->sparse_file_support));
  274. +        superblock->sparse_file_support,
  275. +        superblock->block_clone_support));
  276.  out:
  277.      return status;
  278.  }
  279. @@ -197,6 +205,8 @@ void nfs41_superblock_fs_attributes(
  280.          FsAttrs->FileSystemAttributes |= FILE_CASE_SENSITIVE_SEARCH;
  281.      if (superblock->aclsupport)
  282.          FsAttrs->FileSystemAttributes |= FILE_PERSISTENT_ACLS;
  283. +    if (superblock->block_clone_support)
  284. +        FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_BLOCK_REFCOUNTING;
  285.  
  286.      /* gisburn: Fixme: We should someone query this (NFSv4.2 ?) */
  287.      FsAttrs->MaximumComponentNameLength = NFS41_MAX_COMPONENT_LEN;
  288. diff --git a/daemon/upcall.c b/daemon/upcall.c
  289. index 8643fb5..fe19deb 100644
  290. --- a/daemon/upcall.c
  291. +++ b/daemon/upcall.c
  292. @@ -51,6 +51,7 @@ extern const nfs41_upcall_op nfs41_op_getacl;
  293.  extern const nfs41_upcall_op nfs41_op_setacl;
  294.  extern const nfs41_upcall_op nfs41_op_queryallocatedranges;
  295.  extern const nfs41_upcall_op nfs41_op_setzerodata;
  296. +extern const nfs41_upcall_op nfs41_op_duplicatedata;
  297.  
  298.  /* |_nfs41_opcodes| and |g_upcall_op_table| must be in sync! */
  299.  static const nfs41_upcall_op *g_upcall_op_table[] = {
  300. @@ -76,6 +77,7 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
  301.      &nfs41_op_setacl,
  302.      &nfs41_op_queryallocatedranges,
  303.      &nfs41_op_setzerodata,
  304. +    &nfs41_op_duplicatedata,
  305.      NULL,
  306.      NULL
  307.  };
  308. diff --git a/daemon/upcall.h b/daemon/upcall.h
  309. index fbed276..158b8d4 100644
  310. --- a/daemon/upcall.h
  311. +++ b/daemon/upcall.h
  312. @@ -204,6 +204,13 @@ typedef struct __setzerodata_upcall_args {
  313.      ULONGLONG                   ctime;
  314.  } setzerodata_upcall_args;
  315.  
  316. +typedef struct __duplicatedata_upcall_args {
  317. +    nfs41_open_state    *src_state;
  318. +    LONGLONG            srcfileoffset;
  319. +    LONGLONG            destfileoffset;
  320. +    LONGLONG            bytecount;
  321. +} duplicatedata_upcall_args;
  322. +
  323.  typedef union __upcall_args {
  324.      mount_upcall_args       mount;
  325.      open_upcall_args        open;
  326. @@ -222,6 +229,7 @@ typedef union __upcall_args {
  327.      setacl_upcall_args      setacl;
  328.      queryallocatedranges_upcall_args queryallocatedranges;
  329.      setzerodata_upcall_args setzerodata;
  330. +    duplicatedata_upcall_args duplicatedata;
  331.  } upcall_args;
  332.  
  333.  typedef enum _nfs41_opcodes nfs41_opcodes;
  334. diff --git a/include/nfs41_driver.h b/include/nfs41_driver.h
  335. index 6dce9d9..3837793 100644
  336. --- a/include/nfs41_driver.h
  337. +++ b/include/nfs41_driver.h
  338. @@ -84,6 +84,7 @@ typedef enum _nfs41_opcodes {
  339.      NFS41_SYSOP_ACL_SET,
  340.      NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES,
  341.      NFS41_SYSOP_FSCTL_SET_ZERO_DATA,
  342. +    NFS41_SYSOP_FSCTL_DUPLICATE_DATA,
  343.      NFS41_SYSOP_SHUTDOWN,
  344.      NFS41_SYSOP_INVALID_OPCODE1
  345.  } nfs41_opcodes;
  346. diff --git a/sys/nfs41sys_debug.c b/sys/nfs41sys_debug.c
  347. index d958706..4e0dac7 100644
  348. --- a/sys/nfs41sys_debug.c
  349. +++ b/sys/nfs41sys_debug.c
  350. @@ -679,6 +679,7 @@ const char *opcode2string(int opcode)
  351.      case NFS41_SYSOP_ACL_SET: return "NFS41_SYSOP_ACL_SET";
  352.      case NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES: return "NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES";
  353.      case NFS41_SYSOP_FSCTL_SET_ZERO_DATA: return "NFS41_SYSOP_FSCTL_SET_ZERO_DATA";
  354. +    case NFS41_SYSOP_FSCTL_DUPLICATE_DATA: return "NFS41_SYSOP_FSCTL_DUPLICATE_DATA";
  355.      default: return "UNKNOWN";
  356.      }
  357.  }
  358. diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
  359. index ab47b4e..a237071 100644
  360. --- a/sys/nfs41sys_driver.h
  361. +++ b/sys/nfs41sys_driver.h
  362. @@ -283,6 +283,12 @@ typedef struct _updowncall_entry {
  363.          struct {
  364.              FILE_ZERO_DATA_INFORMATION setzerodata;
  365.          } SetZeroData;
  366. +        struct {
  367. +            void        *src_state;
  368. +            LONGLONG    srcfileoffset;
  369. +            LONGLONG    destfileoffset;
  370. +            LONGLONG    bytecount;
  371. +        } DuplicateData;
  372.      } u;
  373.  
  374.  } nfs41_updowncall_entry;
  375. @@ -665,6 +671,14 @@ NTSTATUS marshal_nfs41_setzerodata(
  376.  NTSTATUS unmarshal_nfs41_setzerodata(
  377.      nfs41_updowncall_entry *cur,
  378.      unsigned char **buf);
  379. +NTSTATUS marshal_nfs41_duplicatedata(
  380. +    nfs41_updowncall_entry *entry,
  381. +    unsigned char *buf,
  382. +    ULONG buf_len,
  383. +    ULONG *len);
  384. +NTSTATUS unmarshal_nfs41_duplicatedata(
  385. +    nfs41_updowncall_entry *cur,
  386. +    unsigned char **buf);
  387.  
  388.  /* nfs41sys_ioctl.c */
  389.  NTSTATUS nfs41_IoCtl(
  390. diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
  391. index ede33e3..3f401ec 100644
  392. --- a/sys/nfs41sys_fsctl.c
  393. +++ b/sys/nfs41sys_fsctl.c
  394. @@ -585,6 +585,251 @@ NTSTATUS unmarshal_nfs41_setzerodata(
  395.      return status;
  396.  }
  397.  
  398. +static
  399. +NTSTATUS check_nfs41_duplicatedata_args(
  400. +    PRX_CONTEXT RxContext)
  401. +{
  402. +    NTSTATUS status = STATUS_SUCCESS;
  403. +    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  404. +    __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
  405. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  406. +
  407. +    /* access checks */
  408. +    if (VNetRootContext->read_only) {
  409. +        status = STATUS_MEDIA_WRITE_PROTECTED;
  410. +        goto out;
  411. +    }
  412. +    if (!(SrvOpen->DesiredAccess &
  413. +        (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES))) {
  414. +        status = STATUS_ACCESS_DENIED;
  415. +        goto out;
  416. +    }
  417. +out:
  418. +    return status;
  419. +}
  420. +
  421. +static
  422. +NTSTATUS nfs41_DuplicateData(
  423. +    IN OUT PRX_CONTEXT RxContext)
  424. +{
  425. +    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  426. +    nfs41_updowncall_entry *entry = NULL;
  427. +    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  428. +    __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
  429. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  430. +    __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
  431. +        NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
  432. +    __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
  433. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  434. +    __notnull PDUPLICATE_EXTENTS_DATA duplicatedatabuffer =
  435. +        (PDUPLICATE_EXTENTS_DATA)FsCtl->pInputBuffer;
  436. +    __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
  437. +    PFILE_OBJECT srcfo = NULL;
  438. +
  439. +    DbgEn();
  440. +
  441. +    RxContext->IoStatusBlock.Information = 0;
  442. +
  443. +    status = check_nfs41_duplicatedata_args(RxContext);
  444. +    if (status)
  445. +        goto out;
  446. +
  447. +    if (FsCtl->pInputBuffer == NULL) {
  448. +        status = STATUS_INVALID_USER_BUFFER;
  449. +        goto out;
  450. +    }
  451. +
  452. +    if (FsCtl->InputBufferLength <
  453. +        sizeof(DUPLICATE_EXTENTS_DATA)) {
  454. +        DbgP("nfs41_DuplicateData: "
  455. +            "buffer to small\n");
  456. +        status = STATUS_BUFFER_TOO_SMALL;
  457. +        goto out;
  458. +    }
  459. +
  460. +    DbgP("nfs41_DuplicateData: "
  461. +        "duplicatedatabuffer=(FileHandle=0x%p,"
  462. +        "SourceFileOffset=%lld,"
  463. +        "TargetFileOffset=%lld,"
  464. +        "ByteCount=%lld)\n",
  465. +        (void *)duplicatedatabuffer->FileHandle,
  466. +        (long long)duplicatedatabuffer->SourceFileOffset.QuadPart,
  467. +        (long long)duplicatedatabuffer->TargetFileOffset.QuadPart,
  468. +        (long long)duplicatedatabuffer->ByteCount.QuadPart);
  469. +
  470. +    if (duplicatedatabuffer->ByteCount.QuadPart == 0LL) {
  471. +        status = STATUS_SUCCESS;
  472. +        goto out;
  473. +    }
  474. +
  475. +    status = ObReferenceObjectByHandle(duplicatedatabuffer->FileHandle,
  476. +        0,
  477. +        *IoFileObjectType,
  478. +        RxContext->CurrentIrp->RequestorMode,
  479. +        (void **)&srcfo,
  480. +        NULL);
  481. +    if (!NT_SUCCESS(status)) {
  482. +        DbgP("nfs41_DuplicateData: "
  483. +            "ObReferenceObjectByHandle returned 0x%lx\n",
  484. +            status);
  485. +        goto out;
  486. +    }
  487. +
  488. +    DbgP("nfs41_DuplicateData: "
  489. +        "srcfo=0x%p srcfo->FileName='%wZ'\n",
  490. +        srcfo,
  491. +        srcfo->FileName);
  492. +
  493. +    if (srcfo->DeviceObject !=
  494. +        RxContext->CurrentIrpSp->FileObject->DeviceObject) {
  495. +        DbgP("nfs41_DuplicateData: "
  496. +            "source and destination are on different volumes\n");
  497. +        status = STATUS_INVALID_PARAMETER;
  498. +        goto out;
  499. +    }
  500. +
  501. +    PFCB srcfcb = srcfo->FsContext;
  502. +    PFOBX srcfox = srcfo->FsContext2;
  503. +    PNFS41_FCB nfs41_src_fcb = NFS41GetFcbExtension(srcfcb);
  504. +    PNFS41_FOBX nfs41_src_fobx = NFS41GetFobxExtension(srcfox);
  505. +
  506. +    if (!nfs41_src_fcb) {
  507. +        DbgP("nfs41_DuplicateData: No nfs41_src_fcb\n");
  508. +        status = STATUS_INVALID_PARAMETER;
  509. +        goto out;
  510. +    }
  511. +
  512. +    if (!nfs41_src_fobx) {
  513. +        DbgP("nfs41_DuplicateData: No nfs41_src_fobx\n");
  514. +        status = STATUS_INVALID_PARAMETER;
  515. +        goto out;
  516. +    }
  517. +
  518. +    /*
  519. +     * Disable caching because NFSv4.2 DEALLOCATE is basically a
  520. +     * "write" operation. AFAIK we should flush the cache and wait
  521. +     * for the kernel lazy writer (which |RxChangeBufferingState()|
  522. +     * AFAIK does) before doing the DEALLOCATE, to avoid that we
  523. +     * have outstanding writes in the kernel cache at the same
  524. +     * location where the DEALLOCATE should do it's work
  525. +     */
  526. +    ULONG flag = DISABLE_CACHING;
  527. +    DbgP("nfs41_DuplicateData: disableing caching for file '%wZ'\n",
  528. +        SrvOpen->pAlreadyPrefixedName);
  529. +    RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
  530. +
  531. +    status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_DUPLICATE_DATA,
  532. +        &nfs41_fobx->sec_ctx,
  533. +        pVNetRootContext->session,
  534. +        nfs41_fobx->nfs41_open_state,
  535. +        pNetRootContext->nfs41d_version,
  536. +        SrvOpen->pAlreadyPrefixedName,
  537. +        &entry);
  538. +
  539. +    if (status)
  540. +        goto out;
  541. +
  542. +    entry->u.DuplicateData.src_state = nfs41_src_fobx->nfs41_open_state;
  543. +    entry->u.DuplicateData.srcfileoffset =
  544. +        duplicatedatabuffer->SourceFileOffset.QuadPart;
  545. +    entry->u.DuplicateData.destfileoffset =
  546. +        duplicatedatabuffer->TargetFileOffset.QuadPart;
  547. +    entry->u.DuplicateData.bytecount =
  548. +        duplicatedatabuffer->ByteCount.QuadPart;
  549. +
  550. +    status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
  551. +
  552. +    if (status) {
  553. +        /* Timeout - |nfs41_downcall()| will free |entry|+contents */
  554. +        goto out;
  555. +    }
  556. +
  557. +    if (entry->psec_ctx == &entry->sec_ctx) {
  558. +        SeDeleteClientSecurity(entry->psec_ctx);
  559. +    }
  560. +    entry->psec_ctx = NULL;
  561. +
  562. +    if (!entry->status) {
  563. +        DbgP("nfs41_DuplicateData: SUCCESS\n");
  564. +        RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
  565. +        RxContext->IoStatusBlock.Information = 0;
  566. +    }
  567. +    else {
  568. +        DbgP("nfs41_DuplicateData: "
  569. +            "FAILURE, entry->status=0x%lx\n", entry->status);
  570. +        status = map_setfile_error(entry->status);
  571. +        RxContext->CurrentIrp->IoStatus.Status = status;
  572. +        RxContext->IoStatusBlock.Information = 0;
  573. +    }
  574. +
  575. +    if (entry) {
  576. +        nfs41_UpcallDestroy(entry);
  577. +    }
  578. +
  579. +out:
  580. +    if (srcfo) {
  581. +        ObDereferenceObject(srcfo);
  582. +    }
  583. +
  584. +    DbgEx();
  585. +    return status;
  586. +}
  587. +
  588. +NTSTATUS marshal_nfs41_duplicatedata(
  589. +    nfs41_updowncall_entry *entry,
  590. +    unsigned char *buf,
  591. +    ULONG buf_len,
  592. +    ULONG *len)
  593. +{
  594. +    NTSTATUS status = STATUS_SUCCESS;
  595. +    ULONG header_len = 0;
  596. +    unsigned char *tmp = buf;
  597. +
  598. +    status = marshal_nfs41_header(entry, tmp, buf_len, len);
  599. +    if (status) goto out;
  600. +    else tmp += *len;
  601. +
  602. +    header_len = *len +
  603. +        sizeof(void *) +
  604. +        3*sizeof(LONGLONG);
  605. +    if (header_len > buf_len) {
  606. +        status = STATUS_INSUFFICIENT_RESOURCES;
  607. +        goto out;
  608. +    }
  609. +
  610. +    RtlCopyMemory(tmp, &entry->u.DuplicateData.src_state,
  611. +        sizeof(entry->u.DuplicateData.src_state));
  612. +    tmp += sizeof(entry->u.DuplicateData.src_state);
  613. +    RtlCopyMemory(tmp, &entry->u.DuplicateData.srcfileoffset,
  614. +        sizeof(entry->u.DuplicateData.srcfileoffset));
  615. +    tmp += sizeof(entry->u.DuplicateData.srcfileoffset);
  616. +    RtlCopyMemory(tmp, &entry->u.DuplicateData.destfileoffset,
  617. +        sizeof(entry->u.DuplicateData.destfileoffset));
  618. +    tmp += sizeof(entry->u.DuplicateData.destfileoffset);
  619. +    RtlCopyMemory(tmp, &entry->u.DuplicateData.bytecount,
  620. +        sizeof(entry->u.DuplicateData.bytecount));
  621. +    tmp += sizeof(entry->u.DuplicateData.bytecount);
  622. +    *len = header_len;
  623. +
  624. +    DbgP("marshal_nfs41_duplicatedata: name='%wZ'\n",
  625. +         entry->filename);
  626. +out:
  627. +    return status;
  628. +}
  629. +
  630. +NTSTATUS unmarshal_nfs41_duplicatedata(
  631. +    nfs41_updowncall_entry *cur,
  632. +    unsigned char **buf)
  633. +{
  634. +    NTSTATUS status = STATUS_SUCCESS;
  635. +
  636. +    RtlCopyMemory(&cur->ChangeTime, *buf, sizeof(ULONGLONG));
  637. +    DbgP("unmarshal_nfs41_duplicatedata: returned ChangeTime %llu\n",
  638. +        cur->ChangeTime);
  639. +
  640. +    return status;
  641. +}
  642. +
  643.  NTSTATUS nfs41_FsCtl(
  644.      IN OUT PRX_CONTEXT RxContext)
  645.  {
  646. @@ -612,6 +857,9 @@ NTSTATUS nfs41_FsCtl(
  647.      case FSCTL_SET_ZERO_DATA:
  648.          status = nfs41_SetZeroData(RxContext);
  649.          break;
  650. +    case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
  651. +        status = nfs41_DuplicateData(RxContext);
  652. +        break;
  653.      default:
  654.          break;
  655.      }
  656. diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
  657. index e9e6eac..5e2edee 100644
  658. --- a/sys/nfs41sys_updowncall.c
  659. +++ b/sys/nfs41sys_updowncall.c
  660. @@ -310,6 +310,10 @@ NTSTATUS handle_upcall(
  661.          status = marshal_nfs41_setzerodata(entry,
  662.              pbOut, cbOut, len);
  663.          break;
  664. +    case NFS41_SYSOP_FSCTL_DUPLICATE_DATA:
  665. +        status = marshal_nfs41_duplicatedata(entry,
  666. +            pbOut, cbOut, len);
  667. +        break;
  668.      default:
  669.          status = STATUS_INVALID_PARAMETER;
  670.          print_error("Unknown nfs41 ops %d\n", entry->opcode);
  671. @@ -674,6 +678,9 @@ NTSTATUS nfs41_downcall(
  672.          case NFS41_SYSOP_FSCTL_SET_ZERO_DATA:
  673.              unmarshal_nfs41_setzerodata(cur, &buf);
  674.              break;
  675. +        case NFS41_SYSOP_FSCTL_DUPLICATE_DATA:
  676. +            unmarshal_nfs41_duplicatedata(cur, &buf);
  677. +            break;
  678.          }
  679.      }
  680.      ExReleaseFastMutex(&cur->lock);
  681. --
  682. 2.45.1
  683.  
  684. From 28936aedca676aaf430831f709533388e00accca Mon Sep 17 00:00:00 2001
  685. From: Roland Mainz <roland.mainz@nrubsig.org>
  686. Date: Tue, 15 Apr 2025 18:41:54 +0200
  687. Subject: [PATCH 4/4] daemon: Implement |FSCTL_DUPLICATE_EXTENTS_TO_FILE| via
  688.  NFS CLONE
  689.  
  690. Implement |FSCTL_DUPLICATE_EXTENTS_TO_FILE| via NFSv4.2 CLONE
  691.  
  692. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  693. ---
  694. daemon/fsctl.c     | 120 +++++++++++++++++++++++++++++++++++++++++----
  695.  daemon/nfs41_ops.h |  24 +++++++++
  696.  daemon/nfs41_xdr.c |   2 +-
  697.  daemon/nfs41_xdr.h |   2 +
  698.  daemon/nfs42_ops.c |  92 ++++++++++++++++++++++++++++++++++
  699.  daemon/nfs42_xdr.c |  42 ++++++++++++++++
  700.  daemon/recovery.c  |   3 ++
  701.  daemon/upcall.h    |   1 +
  702.  8 files changed, 276 insertions(+), 10 deletions(-)
  703.  
  704. diff --git a/daemon/fsctl.c b/daemon/fsctl.c
  705. index fa0c342..91f0763 100644
  706. --- a/daemon/fsctl.c
  707. +++ b/daemon/fsctl.c
  708. @@ -463,31 +463,133 @@ out:
  709.      return status;
  710.  }
  711.  
  712. +/*
  713. + * CLONE_PUNCH_HOLE_IF_CLONESIZE_BIGGER_THAN_SRCFILESIZE - Punch
  714. + * a hole at the end of the file if the clone range is larger than
  715. + * the source file's size (Linux 6.6 nfsd will return
  716. + * |NFS4ERR_INVAL| in such cases)
  717. + *
  718. + * ToDo:
  719. + * - This should be replaced by a NFS SEEK loop to enumerate
  720. + * data ranges and hole ranges - Data ranges are handled via NFS
  721. + * CLONE, hole ranges via NFS DEALLOCATE
  722. + */
  723. +#define CLONE_PUNCH_HOLE_IF_CLONESIZE_BIGGER_THAN_SRCFILESIZE 1
  724. +
  725.  static
  726.  int handle_duplicatedata(void *daemon_context,
  727.      nfs41_upcall *upcall)
  728.  {
  729.      int status = ERROR_INVALID_PARAMETER;
  730.      duplicatedata_upcall_args *args = &upcall->args.duplicatedata;
  731. -    nfs41_open_state *state = upcall->state_ref;
  732. -//    nfs41_session *session = state->session;
  733. -//    nfs41_path_fh *file = &state->file;
  734. +    nfs41_open_state *src_state = args->src_state;
  735. +    nfs41_open_state *dst_state = upcall->state_ref;
  736. +    nfs41_session *session = dst_state->session;
  737. +    nfs41_path_fh *src_file = &src_state->file;
  738. +    nfs41_path_fh *dst_file = &dst_state->file;
  739. +    nfs41_file_info info;
  740. +    stateid_arg src_stateid;
  741. +    stateid_arg dst_stateid;
  742. +    int64_t bytecount;
  743. +
  744. +    (void)memset(&info, 0, sizeof(info));
  745.  
  746.      DPRINTF(DDLVL,
  747.          ("--> handle_duplicatedata("
  748. -            "state->path.path='%s', "
  749. +            "dst_state->path.path='%s', "
  750.              "src_state->path.path='%s')\n",
  751. -            state->path.path,
  752. -            args->src_state->path.path));
  753. +            dst_state->path.path,
  754. +            src_state->path.path));
  755.  
  756.      /* NFS CLONE requires NFSv4.2 */
  757. -    if (state->session->client->root->nfsminorvers < 2) {
  758. +    if (dst_state->session->client->root->nfsminorvers < 2) {
  759.          status = ERROR_NOT_SUPPORTED;
  760.          goto out;
  761.      }
  762.  
  763. -    /* FIXME: Cloning not implemented yet */
  764. -    status = ERROR_NOT_SUPPORTED;
  765. +    nfs41_open_stateid_arg(src_state, &src_stateid);
  766. +    nfs41_open_stateid_arg(dst_state, &dst_stateid);
  767. +
  768. +#ifdef CLONE_PUNCH_HOLE_IF_CLONESIZE_BIGGER_THAN_SRCFILESIZE
  769. +    int64_t src_file_size;
  770. +    bitmap4 attr_request = { .count = 1, .arr[0] = FATTR4_WORD0_SIZE };
  771. +    status = nfs41_getattr(session, src_file, &attr_request, &info);
  772. +    if (status) {
  773. +        eprintf("handle_duplicatedata: "
  774. +            "nfs41_getattr() failed with '%s'\n",
  775. +            nfs_error_string(status));
  776. +        status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  777. +        goto out;
  778. +    }
  779. +    src_file_size = info.size;
  780. +
  781. +    if (args->bytecount > src_file_size)
  782. +        bytecount = src_file_size;
  783. +    else
  784. +        bytecount = args->bytecount;
  785. +#else
  786. +    bytecount = args->bytecount;
  787. +#endif /* CLONE_PUNCH_HOLE_IF_CLONESIZE_BIGGER_THAN_SRCFILESIZE */
  788. +
  789. +    status = nfs42_clone(session,
  790. +        src_file,
  791. +        dst_file,
  792. +        &src_stateid,
  793. +        &dst_stateid,
  794. +        args->srcfileoffset,
  795. +        args->destfileoffset,
  796. +        bytecount,
  797. +        &info);
  798. +    if (status) {
  799. +        DPRINTF(DDLVL,
  800. +            ("handle_duplicatedata("
  801. +            "src_state->path.path='%s' "
  802. +            "dst_state->path.path='%s'): "
  803. +            "CLONE failed with status=0x%x\n",
  804. +            src_state->path.path,
  805. +            dst_state->path.path,
  806. +            status));
  807. +        goto out;
  808. +    }
  809. +
  810. +#ifdef CLONE_PUNCH_HOLE_IF_CLONESIZE_BIGGER_THAN_SRCFILESIZE
  811. +    if (args->bytecount > src_file_size) {
  812. +        DPRINTF(DDLVL,
  813. +            ("handle_duplicatedata(): "
  814. +            "Clone range (%llu) bigger than source file size "
  815. +            "(%llu), adding hole at the end of dest file.\n",
  816. +            args->bytecount,
  817. +            src_file_size));
  818. +
  819. +        status = nfs42_deallocate(session,
  820. +            dst_file,
  821. +            &dst_stateid,
  822. +            src_file_size,
  823. +            (args->bytecount - src_file_size),
  824. +            &info);
  825. +        if (status) {
  826. +            DPRINTF(DDLVL,
  827. +                ("handle_duplicatedata("
  828. +                "src_state->path.path='%s' "
  829. +                "dst_state->path.path='%s'): "
  830. +                "DEALLOCATE failed with status=0x%x\n",
  831. +                src_state->path.path,
  832. +                dst_state->path.path,
  833. +                status));
  834. +            goto out;
  835. +        }
  836. +    }
  837. +#endif /* CLONE_PUNCH_HOLE_IF_CLONESIZE_BIGGER_THAN_SRCFILESIZE */
  838. +
  839. +    /* Update ctime on success */
  840. +    EASSERT(bitmap_isset(&info.attrmask, 0, FATTR4_WORD0_CHANGE));
  841. +    args->ctime = info.change;
  842. +
  843. +    DPRINTF(DDLVL,
  844. +        ("handle_duplicatedata(dst_state->path.path='%s'): "
  845. +        "args->ctime=%llu\n",
  846. +        dst_state->path.path,
  847. +        args->ctime));
  848.  
  849.  out:
  850.      DPRINTF(0,
  851. diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h
  852. index 149bc08..d49346b 100644
  853. --- a/daemon/nfs41_ops.h
  854. +++ b/daemon/nfs41_ops.h
  855. @@ -830,6 +830,19 @@ typedef struct __nfs42_seek_res {
  856.      nfs42_seek_res_ok   resok4;
  857.  } nfs42_seek_res;
  858.  
  859. +/* OP_CLONE */
  860. +typedef struct __nfs42_clone_args {
  861. +    stateid_arg     *src_stateid;
  862. +    stateid_arg     *dst_stateid;
  863. +    uint64_t        src_offset;
  864. +    uint64_t        dst_offset;
  865. +    uint64_t        count;
  866. +} nfs42_clone_args;
  867. +
  868. +typedef struct __nfs42_clone_res {
  869. +    uint32_t        status;
  870. +} nfs42_clone_res;
  871. +
  872.  /* OP_READDIR */
  873.  typedef struct __nfs41_readdir_args {
  874.      nfs41_readdir_cookie    cookie;
  875. @@ -1250,6 +1263,17 @@ int nfs42_seek(
  876.      OUT bool_t *eof_out,
  877.      OUT uint64_t *offset_out);
  878.  
  879. +int nfs42_clone(
  880. +    IN nfs41_session *session,
  881. +    IN nfs41_path_fh *src_file,
  882. +    IN nfs41_path_fh *dst_file,
  883. +    IN stateid_arg *src_stateid,
  884. +    IN stateid_arg *dst_stateid,
  885. +    IN uint64_t src_offset,
  886. +    IN uint64_t dst_offset,
  887. +    IN uint64_t length,
  888. +    OUT nfs41_file_info *cinfo);
  889. +
  890.  int nfs41_commit(
  891.      IN nfs41_session *session,
  892.      IN nfs41_path_fh *file,
  893. diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c
  894. index ecae512..2d651a4 100644
  895. --- a/daemon/nfs41_xdr.c
  896. +++ b/daemon/nfs41_xdr.c
  897. @@ -3672,7 +3672,7 @@ static const op_table_entry g_op_table[] = {
  898.      { encode_op_read_plus, decode_op_read_plus }, /* OP_READ_PLUS = 68, */
  899.      { encode_op_seek, decode_op_seek }, /* OP_SEEK = 69, */
  900.      { NULL, NULL }, /* OP_WRITE_SAME = 70, */
  901. -    { NULL, NULL }, /* OP_CLONE = 71, */
  902. +    { encode_op_clone, decode_op_clone }, /* OP_CLONE = 71, */
  903.  
  904.      /* xattr support (RFC8726) */
  905.      { NULL, NULL }, /* OP_GETXATTR = 72, */
  906. diff --git a/daemon/nfs41_xdr.h b/daemon/nfs41_xdr.h
  907. index 0019ec9..f2f2182 100644
  908. --- a/daemon/nfs41_xdr.h
  909. +++ b/daemon/nfs41_xdr.h
  910. @@ -42,5 +42,7 @@ bool_t encode_op_read_plus(XDR *xdr, nfs_argop4 *argop);
  911.  bool_t decode_op_read_plus(XDR *xdr, nfs_resop4 *resop);
  912.  bool_t encode_op_seek(XDR *xdr, nfs_argop4 *argop);
  913.  bool_t decode_op_seek(XDR *xdr, nfs_resop4 *resop);
  914. +bool_t encode_op_clone(XDR *xdr, nfs_argop4 *argop);
  915. +bool_t decode_op_clone(XDR *xdr, nfs_resop4 *resop);
  916.  
  917.  #endif /* !__NFS41_NFS_XDR_H__ */
  918. diff --git a/daemon/nfs42_ops.c b/daemon/nfs42_ops.c
  919. index f416986..dc5a769 100644
  920. --- a/daemon/nfs42_ops.c
  921. +++ b/daemon/nfs42_ops.c
  922. @@ -302,3 +302,95 @@ int nfs42_seek(
  923.  out:
  924.      return status;
  925.  }
  926. +
  927. +int nfs42_clone(
  928. +    IN nfs41_session *session,
  929. +    IN nfs41_path_fh *src_file,
  930. +    IN nfs41_path_fh *dst_file,
  931. +    IN stateid_arg *src_stateid,
  932. +    IN stateid_arg *dst_stateid,
  933. +    IN uint64_t src_offset,
  934. +    IN uint64_t dst_offset,
  935. +    IN uint64_t length,
  936. +    OUT nfs41_file_info *cinfo)
  937. +{
  938. +    int status;
  939. +    nfs41_compound compound;
  940. +    nfs_argop4 argops[7];
  941. +    nfs_resop4 resops[7];
  942. +    nfs41_sequence_args sequence_args;
  943. +    nfs41_sequence_res sequence_res;
  944. +    nfs41_putfh_args src_putfh_args;
  945. +    nfs41_putfh_res src_putfh_res;
  946. +    nfs41_savefh_res savefh_res;
  947. +    nfs41_putfh_args dst_putfh_args;
  948. +    nfs41_putfh_res dst_putfh_res;
  949. +    nfs42_clone_args clone_args;
  950. +    nfs42_clone_res clone_res;
  951. +    nfs41_getattr_args getattr_args;
  952. +    nfs41_getattr_res getattr_res = {0};
  953. +    bitmap4 attr_request;
  954. +    nfs41_file_info info, *pinfo;
  955. +
  956. +    nfs41_superblock_getattr_mask(dst_file->fh.superblock, &attr_request);
  957. +
  958. +    /* FIXME: What about DS in pNFS case ? */
  959. +    compound_init(&compound, session->client->root->nfsminorvers,
  960. +        argops, resops, "clone");
  961. +
  962. +    compound_add_op(&compound, OP_SEQUENCE,
  963. +        &sequence_args, &sequence_res);
  964. +    nfs41_session_sequence(&sequence_args, session, 0);
  965. +
  966. +    compound_add_op(&compound, OP_PUTFH, &src_putfh_args, &src_putfh_res);
  967. +    src_putfh_args.file = src_file;
  968. +    src_putfh_args.in_recovery = 0;
  969. +
  970. +    compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res);
  971. +
  972. +    compound_add_op(&compound, OP_PUTFH, &dst_putfh_args, &dst_putfh_res);
  973. +    dst_putfh_args.file = dst_file;
  974. +    dst_putfh_args.in_recovery = 0;
  975. +
  976. +    compound_add_op(&compound, OP_CLONE, &clone_args, &clone_res);
  977. +    clone_args.src_stateid = src_stateid;
  978. +    clone_args.dst_stateid = dst_stateid;
  979. +    clone_args.src_offset = src_offset;
  980. +    clone_args.dst_offset = dst_offset;
  981. +    clone_args.count = length;
  982. +
  983. +    if (cinfo) {
  984. +        pinfo = cinfo;
  985. +    }
  986. +    else {
  987. +        (void)memset(&info, 0, sizeof(info));
  988. +        pinfo = &info;
  989. +    }
  990. +
  991. +    /*
  992. +     * NFSv4.2 CLONE is some kind of "write" operation and
  993. +     * affects the number of physical bytes allocated, so we have
  994. +     * to do a GETATTR after CLONE to get updates for our cache
  995. +     */
  996. +    compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res);
  997. +    getattr_args.attr_request = &attr_request;
  998. +    getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
  999. +    getattr_res.info = pinfo;
  1000. +
  1001. +    status = compound_encode_send_decode(session, &compound, TRUE);
  1002. +    if (status)
  1003. +        goto out;
  1004. +
  1005. +    if (compound_error(status = compound.res.status))
  1006. +        goto out;
  1007. +
  1008. +    /* update the attribute cache */
  1009. +    bitmap4_cpy(&pinfo->attrmask, &getattr_res.obj_attributes.attrmask);
  1010. +    nfs41_attr_cache_update(session_name_cache(session),
  1011. +        dst_file->fh.fileid, pinfo);
  1012. +
  1013. +    nfs41_superblock_space_changed(dst_file->fh.superblock);
  1014. +
  1015. +out:
  1016. +    return status;
  1017. +}
  1018. diff --git a/daemon/nfs42_xdr.c b/daemon/nfs42_xdr.c
  1019. index 12d133b..ab7248e 100644
  1020. --- a/daemon/nfs42_xdr.c
  1021. +++ b/daemon/nfs42_xdr.c
  1022. @@ -332,3 +332,45 @@ bool_t decode_op_seek(
  1023.  
  1024.      return TRUE;
  1025.  }
  1026. +
  1027. +/*
  1028. + * OP_CLONE
  1029. + */
  1030. +bool_t encode_op_clone(
  1031. +    XDR *xdr,
  1032. +    nfs_argop4 *argop)
  1033. +{
  1034. +    nfs42_clone_args *args = (nfs42_clone_args *)argop->arg;
  1035. +
  1036. +    if (unexpected_op(argop->op, OP_CLONE))
  1037. +        return FALSE;
  1038. +
  1039. +    if (!xdr_stateid4(xdr, &args->src_stateid->stateid))
  1040. +        return FALSE;
  1041. +
  1042. +    if (!xdr_stateid4(xdr, &args->dst_stateid->stateid))
  1043. +        return FALSE;
  1044. +
  1045. +    if (!xdr_u_hyper(xdr, &args->src_offset))
  1046. +        return FALSE;
  1047. +
  1048. +    if (!xdr_u_hyper(xdr, &args->dst_offset))
  1049. +        return FALSE;
  1050. +
  1051. +    return xdr_u_hyper(xdr, &args->count);
  1052. +}
  1053. +
  1054. +bool_t decode_op_clone(
  1055. +    XDR *xdr,
  1056. +    nfs_resop4 *resop)
  1057. +{
  1058. +    nfs42_clone_res *res = (nfs42_clone_res *)resop->res;
  1059. +
  1060. +    if (unexpected_op(resop->op, OP_CLONE))
  1061. +        return FALSE;
  1062. +
  1063. +    if (!xdr_u_int32_t(xdr, &res->status))
  1064. +        return FALSE;
  1065. +
  1066. +    return TRUE;
  1067. +}
  1068. diff --git a/daemon/recovery.c b/daemon/recovery.c
  1069. index 66bf25e..c3dd695 100644
  1070. --- a/daemon/recovery.c
  1071. +++ b/daemon/recovery.c
  1072. @@ -820,6 +820,9 @@ bool_t nfs41_recover_stateid(
  1073.      } else if (argop->op == OP_SEEK) {
  1074.          nfs42_seek_args *seek = (nfs42_seek_args *)argop->arg;
  1075.          stateid = seek->stateid;
  1076. +    } else if (argop->op == OP_CLONE) {
  1077. +        nfs42_clone_args *clone = (nfs42_clone_args *)argop->arg;
  1078. +        stateid = clone->dst_stateid;
  1079.      } else if (argop->op == OP_WRITE) {
  1080.          nfs41_write_args *write = (nfs41_write_args*)argop->arg;
  1081.          stateid = write->stateid;
  1082. diff --git a/daemon/upcall.h b/daemon/upcall.h
  1083. index 158b8d4..c14adc7 100644
  1084. --- a/daemon/upcall.h
  1085. +++ b/daemon/upcall.h
  1086. @@ -209,6 +209,7 @@ typedef struct __duplicatedata_upcall_args {
  1087.      LONGLONG            srcfileoffset;
  1088.      LONGLONG            destfileoffset;
  1089.      LONGLONG            bytecount;
  1090. +    ULONGLONG           ctime;
  1091.  } duplicatedata_upcall_args;
  1092.  
  1093.  typedef union __upcall_args {
  1094. --
  1095. 2.45.1

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at