pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


FSCTL for deleg control
Posted by Anonymous on Wed 9th Sep 2026 17:00
raw | new post

  1. diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
  2. index e0b99cb..f79d37d 100644
  3. --- a/daemon/daemon_debug.c
  4. +++ b/daemon/daemon_debug.c
  5. @@ -490,6 +490,8 @@ const char* opcode2string(nfs41_opcodes opcode)
  6.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY)
  7.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO)
  8.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO)
  9. +        NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_REQUEST_DELEGATION)
  10. +        NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_RETURN_DELEGATION)
  11.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL)
  12.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_SHUTDOWN)
  13.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_INVALID_OPCODE1)
  14. diff --git a/daemon/delegation.c b/daemon/delegation.c
  15. index 28bbfe0..33061ff 100644
  16. --- a/daemon/delegation.c
  17. +++ b/daemon/delegation.c
  18. @@ -449,6 +449,36 @@ static int delegation_find(
  19.      return status;
  20.  }
  21.  
  22. +int nfs41_delegation_return_file(
  23. +    IN nfs41_session *session,
  24. +    IN nfs41_path_fh *file)
  25. +{
  26. +    nfs41_client *client = session->client;
  27. +    nfs41_delegation_state *deleg;
  28. +    int status;
  29. +
  30. +    status = delegation_find(client, &file->fh, deleg_file_cmp, &deleg);
  31. +    if (status)
  32. +        return status;
  33. +
  34. +    AcquireSRWLockExclusive(&deleg->lock);
  35. +    if (deleg->status == DELEGATION_GRANTED) {
  36. +        deleg->status = DELEGATION_RETURNING;
  37. +        status = NFS4_OK;
  38. +    } else {
  39. +        while (deleg->status == DELEGATION_RETURNING)
  40. +            SleepConditionVariableSRW(&deleg->cond, &deleg->lock, INFINITE, 0);
  41. +        status = NFS4ERR_BADHANDLE;
  42. +    }
  43. +    ReleaseSRWLockExclusive(&deleg->lock);
  44. +
  45. +    if (status == NFS4_OK)
  46. +        status = delegation_return(client, deleg, FALSE, TRUE);
  47. +
  48. +    nfs41_delegation_deref(deleg);
  49. +    return status;
  50. +}
  51. +
  52.  int nfs41_delegation_get_type(
  53.      IN nfs41_client *client,
  54.      IN const nfs41_fh *fh,
  55. diff --git a/daemon/delegation.h b/daemon/delegation.h
  56. index ebca425..bdb4376 100644
  57. --- a/daemon/delegation.h
  58. +++ b/daemon/delegation.h
  59. @@ -96,6 +96,10 @@ int nfs41_client_delegation_recall_any(
  60.      IN bool recall_read_delegs,
  61.      IN bool recall_write_delegs);
  62.  
  63. +int nfs41_delegation_return_file(
  64. +    IN nfs41_session *session,
  65. +    IN nfs41_path_fh *file);
  66. +
  67.  int nfs41_delegation_get_type(
  68.      IN nfs41_client *client,
  69.      IN const nfs41_fh *fh,
  70. diff --git a/daemon/fsctl.c b/daemon/fsctl.c
  71. index 936f634..4e5adac 100644
  72. --- a/daemon/fsctl.c
  73. +++ b/daemon/fsctl.c
  74. @@ -1405,3 +1405,132 @@ const nfs41_upcall_op nfs41_op_querydelegationinfo = {
  75.      .marshall = marshall_querydelegationinfo,
  76.      .arg_size = sizeof(querydelegationinfo_upcall_args)
  77.  };
  78. +
  79. +static int parse_requestdelegation(const unsigned char *restrict buffer,
  80. +    uint32_t length, nfs41_upcall *upcall)
  81. +{
  82. +    int status;
  83. +
  84. +    status = safe_read(&buffer, &length,
  85. +        &upcall->args.requestdelegation.requested_type,
  86. +        sizeof(upcall->args.requestdelegation.requested_type));
  87. +    if (status) goto out;
  88. +
  89. +    EASSERT(length == 0);
  90. +
  91. +out:
  92. +    return ERROR_SUCCESS;
  93. +}
  94. +
  95. +static int handle_requestdelegation(void *daemon_context, nfs41_upcall *upcall)
  96. +{
  97. +    nfs41_open_state *state = upcall->state_ref;
  98. +    enum open_delegation_type4 current;
  99. +    enum open_delegation_type4 requested = (enum open_delegation_type4)
  100. +        upcall->args.requestdelegation.requested_type;
  101. +    open_delegation4 delegation = { 0 };
  102. +    nfs41_delegation_state *deleg_state = NULL;
  103. +    deleg_claim4 claim = { CLAIM_FH, 0 };
  104. +    uint32_t want;
  105. +    int status;
  106. +
  107. +    if ((state == NULL) || (state->session == NULL))
  108. +        return ERROR_INVALID_HANDLE;
  109. +    if ((requested != OPEN_DELEGATE_READ) && (requested != OPEN_DELEGATE_WRITE))
  110. +        return ERROR_INVALID_PARAMETER;
  111. +
  112. +    status = nfs41_delegation_get_type(state->session->client,
  113. +        &state->file.fh, &current);
  114. +    if (status == NFS4_OK)
  115. +        return ERROR_ALREADY_EXISTS;
  116. +    if (status != NFS4ERR_BADHANDLE)
  117. +        return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  118. +
  119. +    want = requested == OPEN_DELEGATE_READ ?
  120. +        OPEN4_SHARE_ACCESS_WANT_READ_DELEG : OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG;
  121. +    status = nfs41_want_delegation(state->session, &state->file,
  122. +        &claim, want, TRUE, &delegation);
  123. +    if (status)
  124. +        return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  125. +
  126. +    upcall->args.requestdelegation.deleg_type = (ULONG)delegation.type;
  127. +    upcall->args.requestdelegation.why_no_delegation =
  128. +        delegation.type == OPEN_DELEGATE_NONE_EXT ?
  129. +            (ULONG)delegation.why_no_delegation : 0UL;
  130. +
  131. +    if ((delegation.type == OPEN_DELEGATE_READ) ||
  132. +        (delegation.type == OPEN_DELEGATE_WRITE)) {
  133. +        status = nfs41_delegation_granted(state->session, &state->parent,
  134. +            &state->file, &delegation, TRUE, &deleg_state);
  135. +        if (status)
  136. +            return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  137. +        nfs41_delegation_deref(deleg_state);
  138. +    }
  139. +
  140. +    return ERROR_SUCCESS;
  141. +}
  142. +
  143. +static int marshall_requestdelegation(unsigned char *restrict buffer,
  144. +    uint32_t *restrict length, nfs41_upcall *restrict upcall)
  145. +{
  146. +    int status;
  147. +
  148. +    status = safe_write(&buffer, length,
  149. +        &upcall->args.requestdelegation.deleg_type,
  150. +        sizeof(upcall->args.requestdelegation.deleg_type));
  151. +    if (status) goto out;
  152. +    status = safe_write(&buffer, length,
  153. +        &upcall->args.requestdelegation.why_no_delegation,
  154. +        sizeof(upcall->args.requestdelegation.why_no_delegation));
  155. +out:
  156. +    return status;
  157. +}
  158. +
  159. +const nfs41_upcall_op nfs41_op_requestdelegation = {
  160. +    .parse = parse_requestdelegation,
  161. +    .handle = handle_requestdelegation,
  162. +    .marshall = marshall_requestdelegation,
  163. +    .arg_size = sizeof(requestdelegation_upcall_args)
  164. +};
  165. +
  166. +static int handle_returndelegation(void *daemon_context, nfs41_upcall *upcall)
  167. +{
  168. +    nfs41_open_state *state = upcall->state_ref;
  169. +    enum open_delegation_type4 current;
  170. +    int status;
  171. +
  172. +    if ((state == NULL) || (state->session == NULL))
  173. +        return ERROR_INVALID_HANDLE;
  174. +
  175. +    status = nfs41_delegation_get_type(state->session->client,
  176. +        &state->file.fh, &current);
  177. +    if (status == NFS4ERR_BADHANDLE)
  178. +        return ERROR_NOT_FOUND;
  179. +    if (status)
  180. +        return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  181. +
  182. +    status = nfs41_delegation_return_file(state->session, &state->file);
  183. +    if (status == NFS4ERR_BADHANDLE)
  184. +        return ERROR_NOT_FOUND;
  185. +    return status ?
  186. +        nfs_to_windows_error(status, ERROR_BAD_NET_RESP) : ERROR_SUCCESS;
  187. +}
  188. +
  189. +static int parse_returndelegation(const unsigned char *restrict buffer,
  190. +    uint32_t length, nfs41_upcall *upcall)
  191. +{
  192. +    return (length == 0) ? ERROR_SUCCESS : ERROR_BAD_LENGTH;
  193. +}
  194. +
  195. +static int marshall_returndelegation(unsigned char *restrict buffer,
  196. +    uint32_t *restrict length, nfs41_upcall *restrict upcall)
  197. +{
  198. +    return ERROR_SUCCESS;
  199. +}
  200. +
  201. +const nfs41_upcall_op nfs41_op_returndelegation = {
  202. +    .parse = parse_returndelegation,
  203. +    .handle = handle_returndelegation,
  204. +    .marshall = marshall_returndelegation,
  205. +    .arg_size = 0
  206. +};
  207. diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h
  208. index d3fc3b1..9772a99 100644
  209. --- a/daemon/nfs41_ops.h
  210. +++ b/daemon/nfs41_ops.h
  211. @@ -994,9 +994,9 @@ typedef struct __nfs41_setattr_res {
  212.  
  213.  /* OP_WANT_DELEGATION */
  214.  typedef struct __deleg_claim4 {
  215. -    uint32_t                claim;
  216. +    enum open_claim_type4       claim;
  217.      /* case CLAIM_PREVIOUS: */
  218. -    uint32_t                prev_delegate_type;
  219. +    enum open_delegation_type4  prev_delegate_type;
  220.  } deleg_claim4;
  221.  
  222.  typedef struct __nfs41_want_delegation_args {
  223. diff --git a/daemon/nfs41_types.h b/daemon/nfs41_types.h
  224. index 6b1cf12..830926e 100644
  225. --- a/daemon/nfs41_types.h
  226. +++ b/daemon/nfs41_types.h
  227. @@ -148,6 +148,8 @@ typedef struct __open_delegation4 {
  228.      stateid4 stateid;
  229.      nfsace4 permissions;
  230.      enum open_delegation_type4 type;
  231. +    uint32_t why_no_delegation;
  232. +    bool_t will_signal;
  233.      bool_t recalled;
  234.  } open_delegation4;
  235.  
  236. diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c
  237. index 46061a5..ceb3f18 100644
  238. --- a/daemon/nfs41_xdr.c
  239. +++ b/daemon/nfs41_xdr.c
  240. @@ -2340,17 +2340,15 @@ static bool_t decode_open_none_delegation4(
  241.      XDR *xdr,
  242.      open_delegation4 *delegation)
  243.  {
  244. -    enum_t why_no_deleg;
  245. -    bool_t will_signal;
  246. -
  247. -    if (!xdr_enum(xdr, (enum_t*)&why_no_deleg))
  248. +    if (!xdr_enum(xdr, (enum_t*)&delegation->why_no_delegation))
  249.          return FALSE;
  250.  
  251. -    switch (why_no_deleg)
  252. +    delegation->will_signal = FALSE;
  253. +    switch (delegation->why_no_delegation)
  254.      {
  255.      case WND4_CONTENTION:
  256.      case WND4_RESOURCE:
  257. -        return xdr_bool(xdr, &will_signal);
  258. +        return xdr_bool(xdr, &delegation->will_signal);
  259.      default:
  260.          return TRUE;
  261.      }
  262. @@ -3057,6 +3055,27 @@ static bool_t decode_op_setattr(
  263.  /*
  264.   * OP_WANT_DELEGATION
  265.   */
  266. +static bool_t encode_deleg_claim4(
  267. +    XDR *xdr,
  268. +    deleg_claim4 *claim)
  269. +{
  270. +    if (!xdr_enum(xdr, (enum_t *)&claim->claim))
  271. +        return FALSE;
  272. +
  273. +    switch (claim->claim)
  274. +    {
  275. +        case CLAIM_FH:
  276. +        case CLAIM_DELEG_PREV_FH:
  277. +            return TRUE;
  278. +        case CLAIM_PREVIOUS:
  279. +            return xdr_enum(xdr, (enum_t *)&claim->prev_delegate_type);
  280. +        default:
  281. +            eprintf("encode_deleg_claim4: unsupported claim=%d\n",
  282. +                (int)claim->claim);
  283. +        return FALSE;
  284. +    }
  285. +}
  286. +
  287.  static bool_t encode_op_want_delegation(
  288.      XDR *xdr,
  289.      nfs_argop4 *argop)
  290. @@ -3069,11 +3088,7 @@ static bool_t encode_op_want_delegation(
  291.      if (!xdr_uint32_t(xdr, &args->want))
  292.          return FALSE;
  293.  
  294. -    if (!xdr_uint32_t(xdr, &args->claim->claim))
  295. -        return FALSE;
  296. -
  297. -    return args->claim->claim != CLAIM_PREVIOUS ||
  298. -        xdr_uint32_t(xdr, &args->claim->prev_delegate_type);
  299. +    return encode_deleg_claim4(xdr, args->claim);
  300.  }
  301.  
  302.  static bool_t decode_op_want_delegation(
  303. @@ -3106,8 +3121,9 @@ static bool_t decode_op_want_delegation(
  304.      case OPEN_DELEGATE_WRITE:
  305.          return decode_open_write_delegation4(xdr, res->delegation);
  306.      default:
  307. -        eprintf("decode_open_res_ok: delegation type %d not "
  308. -            "supported.\n", res->delegation->type);
  309. +        eprintf("decode_op_want_delegation: "
  310. +            "delegation type=%d not supported\n",
  311. +            (int)res->delegation->type);
  312.          return FALSE;
  313.      }
  314.  }
  315. diff --git a/daemon/upcall.c b/daemon/upcall.c
  316. index 0e1f43e..ece7fed 100644
  317. --- a/daemon/upcall.c
  318. +++ b/daemon/upcall.c
  319. @@ -56,6 +56,8 @@ extern const nfs41_upcall_op nfs41_op_duplicatedata;
  320.  extern const nfs41_upcall_op nfs41_op_offload_datacopy;
  321.  extern const nfs41_upcall_op nfs41_op_queryidmapinfo;
  322.  extern const nfs41_upcall_op nfs41_op_querydelegationinfo;
  323. +extern const nfs41_upcall_op nfs41_op_requestdelegation;
  324. +extern const nfs41_upcall_op nfs41_op_returndelegation;
  325.  extern const nfs41_upcall_op nfs41_op_setdaemondebuglevel;
  326.  
  327.  /* |_nfs41_opcodes| and |g_upcall_op_table| must be in sync! */
  328. @@ -86,6 +88,8 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
  329.      &nfs41_op_offload_datacopy,
  330.      &nfs41_op_queryidmapinfo,
  331.      &nfs41_op_querydelegationinfo,
  332. +    &nfs41_op_requestdelegation,
  333. +    &nfs41_op_returndelegation,
  334.      &nfs41_op_setdaemondebuglevel,
  335.      NULL, /* NFS41_SYSOP_SHUTDOWN */
  336.      NULL
  337. @@ -172,12 +176,14 @@ int upcall_parse(
  338.  
  339.      if (op) {
  340.          /*
  341. -         * |NFS41_SYSOP_SYMLINK_GET|+|NFS41_SYSOP_UNMOUNT| has 0 payload,
  342. +         * { |NFS41_SYSOP_SYMLINK_GET|, |NFS41_SYSOP_UNMOUNT|,
  343. +         * |NFS41_SYSOP_FSCTL_RETURN_DELEGATION| } have a 0byte payload,
  344.           * |NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL| has a |ULONG| payload
  345.           */
  346.          if ((upcall_upcode != NFS41_SYSOP_SYMLINK_GET) &&
  347.              (upcall_upcode != NFS41_SYSOP_UNMOUNT) &&
  348. -            (upcall_upcode != NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL)) {
  349. +            (upcall_upcode != NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL) &&
  350. +            (upcall_upcode != NFS41_SYSOP_FSCTL_RETURN_DELEGATION)) {
  351.              EASSERT_MSG(op->arg_size >= sizeof(void*),
  352.                  ("upcall->opcode=%u, op->arg_size=%ld\n",
  353.                  (unsigned int)upcall_upcode,
  354. @@ -187,10 +193,12 @@ int upcall_parse(
  355.      }
  356.  
  357.      if (op && op->parse) {
  358. -        /* |NFS41_SYSOP_UNMOUNT| has 0 payload */
  359. +        /* Skip opcalls with 0 payload */
  360.          if ((upcall_upcode != NFS41_SYSOP_SYMLINK_GET) &&
  361.              (upcall_upcode != NFS41_SYSOP_UNMOUNT) &&
  362. -            (upcall_upcode != NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO)) {
  363. +            (upcall_upcode != NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO) &&
  364. +            (upcall_upcode != NFS41_SYSOP_FSCTL_REQUEST_DELEGATION) &&
  365. +            (upcall_upcode != NFS41_SYSOP_FSCTL_RETURN_DELEGATION)) {
  366.              EASSERT(length > 0);
  367.          }
  368.  
  369. diff --git a/daemon/upcall.h b/daemon/upcall.h
  370. index 7baad6c..ec0bf55 100644
  371. --- a/daemon/upcall.h
  372. +++ b/daemon/upcall.h
  373. @@ -258,6 +258,12 @@ typedef struct __querydelegationinfo_upcall_args {
  374.      ULONG deleg_type;
  375.  } querydelegationinfo_upcall_args;
  376.  
  377. +typedef struct __requestdelegation_upcall_args {
  378. +    ULONG requested_type;
  379. +    ULONG deleg_type;
  380. +    ULONG why_no_delegation;
  381. +} requestdelegation_upcall_args;
  382. +
  383.  typedef struct __setdaemondebuglevel_upcall_args {
  384.      LONG debuglevel;
  385.  } setdaemondebuglevel_upcall_args;
  386. @@ -284,6 +290,7 @@ typedef union __upcall_args {
  387.      duplicatedata_upcall_args duplicatedata;
  388.      queryidmapinfo_upcall_args queryidmapinfo;
  389.      querydelegationinfo_upcall_args querydelegationinfo;
  390. +    requestdelegation_upcall_args requestdelegation;
  391.      setdaemondebuglevel_upcall_args setdaemondebuglevel;
  392.  } upcall_args;
  393.  
  394. diff --git a/include/nfs41_driver.h b/include/nfs41_driver.h
  395. index 1e0b7d6..726e649 100644
  396. --- a/include/nfs41_driver.h
  397. +++ b/include/nfs41_driver.h
  398. @@ -116,6 +116,14 @@ typedef struct _FILE_NFS41_QUERY_DELEGATION_INFORMATION {
  399.  } FILE_NFS41_QUERY_DELEGATION_INFORMATION,
  400.      *PFILE_NFS41_QUERY_DELEGATION_INFORMATION;
  401.  
  402. +#define FSCTL_NFS41_REQUEST_DELEGATION \
  403. +    CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800+66, METHOD_BUFFERED, \
  404. +        FILE_READ_DATA | FILE_WRITE_DATA)
  405. +
  406. +#define FSCTL_NFS41_RETURN_DELEGATION \
  407. +    CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800+67, METHOD_BUFFERED, \
  408. +        FILE_READ_DATA | FILE_WRITE_DATA)
  409. +
  410.  /*
  411.   * NFS41_SYS_MAX_PATH_LEN - Maximum path length
  412.   * Notes:
  413. @@ -162,11 +170,25 @@ typedef enum _nfs41_opcodes {
  414.      NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY,
  415.      NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO,
  416.      NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO,
  417. +    NFS41_SYSOP_FSCTL_REQUEST_DELEGATION,
  418. +    NFS41_SYSOP_FSCTL_RETURN_DELEGATION,
  419.      NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL,
  420.      NFS41_SYSOP_SHUTDOWN,
  421.      NFS41_SYSOP_INVALID_OPCODE1
  422.  } nfs41_opcodes;
  423.  
  424. +typedef enum _nfs41_why_no_delegation {
  425. +    NFS41_WND4_NOT_WANTED = 0,
  426. +    NFS41_WND4_CONTENTION = 1,
  427. +    NFS41_WND4_RESOURCE = 2,
  428. +    NFS41_WND4_NOT_SUPP_FTYPE = 3,
  429. +    NFS41_WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4,
  430. +    NFS41_WND4_NOT_SUPP_UPGRADE = 5,
  431. +    NFS41_WND4_NOT_SUPP_DOWNGRADE = 6,
  432. +    NFS41_WND4_CANCELED = 7,
  433. +    NFS41_WND4_IS_DIR = 8
  434. +} nfs41_why_no_delegation;
  435. +
  436.  /* Same as "daemon/nfs41_ops.h" |open_delegation_type4| */
  437.  typedef enum _nfs41_open_delegation_type {
  438.      NFS41_OPEN_DELEGATE_NONE      = 0,
  439. @@ -179,6 +201,12 @@ typedef enum _nfs41_open_delegation_type {
  440.      (((dt) == NFS41_OPEN_DELEGATE_NONE) || \
  441.       ((dt) == NFS41_OPEN_DELEGATE_NONE_EXT))
  442.  
  443. +typedef struct _FILE_NFS41_REQUEST_DELEGATION_RESULT {
  444. +    nfs41_open_delegation_type DelegType;
  445. +    nfs41_why_no_delegation WhyNoDelegation;
  446. +} FILE_NFS41_REQUEST_DELEGATION_RESULT,
  447. +    *PFILE_NFS41_REQUEST_DELEGATION_RESULT;
  448. +
  449.  /*
  450.   * Same as |FILE_FS_ATTRIBUTE_INFORMATION| but with inline buffer
  451.   * for 32 characters
  452. diff --git a/sys/nfs41sys_debug.c b/sys/nfs41sys_debug.c
  453. index 09f41fa..8739c13 100644
  454. --- a/sys/nfs41sys_debug.c
  455. +++ b/sys/nfs41sys_debug.c
  456. @@ -716,6 +716,8 @@ const char *opcode2string(nfs41_opcodes opcode)
  457.      case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
  458.          return "NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY";
  459.      case NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO: return "NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO";
  460. +    case NFS41_SYSOP_FSCTL_REQUEST_DELEGATION: return "NFS41_SYSOP_FSCTL_REQUEST_DELEGATION";
  461. +    case NFS41_SYSOP_FSCTL_RETURN_DELEGATION: return "NFS41_SYSOP_FSCTL_RETURN_DELEGATION";
  462.      default: return "UNKNOWN";
  463.      }
  464.  }
  465. diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
  466. index 32e99c3..44a231c 100644
  467. --- a/sys/nfs41sys_driver.h
  468. +++ b/sys/nfs41sys_driver.h
  469. @@ -362,6 +362,11 @@ typedef struct _updowncall_entry {
  470.              ULONGLONG fileid;
  471.              ULONG deleg_type;
  472.          } QueryDelegationInfo;
  473. +        struct {
  474. +            ULONG requested_type;
  475. +            ULONG deleg_type;
  476. +            ULONG why_no_delegation;
  477. +        } RequestDelegation;
  478.          struct {
  479.              FILE_ZERO_DATA_INFORMATION setzerodata;
  480.          } SetZeroData;
  481. @@ -795,6 +800,14 @@ NTSTATUS marshal_nfs41_querydelegationinfo(
  482.  NTSTATUS unmarshal_nfs41_querydelegationinfo(
  483.      nfs41_updowncall_entry *cur,
  484.      const unsigned char *restrict *restrict buf);
  485. +NTSTATUS marshal_nfs41_requestdelegation(
  486. +    nfs41_updowncall_entry *entry,
  487. +    unsigned char *buf,
  488. +    ULONG buf_len,
  489. +    ULONG *len);
  490. +NTSTATUS unmarshal_nfs41_requestdelegation(
  491. +    nfs41_updowncall_entry *cur,
  492. +    const unsigned char *restrict *restrict buf);
  493.  
  494.  /* nfs41sys_ioctl.c */
  495.  NTSTATUS nfs41_IoCtl(
  496. diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
  497. index 87040f0..e4806c8 100644
  498. --- a/sys/nfs41sys_fsctl.c
  499. +++ b/sys/nfs41sys_fsctl.c
  500. @@ -1794,6 +1794,169 @@ NTSTATUS unmarshal_nfs41_querydelegationinfo(
  501.      return STATUS_SUCCESS;
  502.  }
  503.  
  504. +
  505. +static NTSTATUS nfs41_RequestDelegation(
  506. +    IN OUT PRX_CONTEXT RxContext)
  507. +{
  508. +    NTSTATUS status;
  509. +    nfs41_updowncall_entry *entry = NULL;
  510. +    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  511. +    PNFS41_SRV_OPEN nfs41_srvopen = NFS41GetSrvOpenExtension(SrvOpen);
  512. +    PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
  513. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  514. +    PNFS41_NETROOT_EXTENSION pNetRootContext =
  515. +        NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
  516. +    XXCTL_LOWIO_COMPONENT *FsCtl =
  517. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  518. +    const nfs41_open_delegation_type *input;
  519. +    PFILE_NFS41_REQUEST_DELEGATION_RESULT output;
  520. +
  521. +    RxContext->IoStatusBlock.Information = 0;
  522. +
  523. +    if ((FsCtl->pInputBuffer == NULL) ||
  524. +        (FsCtl->InputBufferLength != sizeof(*input)))
  525. +        return STATUS_INVALID_PARAMETER;
  526. +
  527. +    input = (const nfs41_open_delegation_type *)FsCtl->pInputBuffer;
  528. +    if ((*input != NFS41_OPEN_DELEGATE_READ) &&
  529. +        (*input != NFS41_OPEN_DELEGATE_WRITE))
  530. +        return STATUS_INVALID_PARAMETER;
  531. +
  532. +    if ((FsCtl->pOutputBuffer == NULL) ||
  533. +        (FsCtl->OutputBufferLength <
  534. +        sizeof(FILE_NFS41_REQUEST_DELEGATION_RESULT))) {
  535. +        RxContext->InformationToReturn =
  536. +            sizeof(FILE_NFS41_REQUEST_DELEGATION_RESULT);
  537. +        return STATUS_BUFFER_TOO_SMALL;
  538. +    }
  539. +    output = (PFILE_NFS41_REQUEST_DELEGATION_RESULT)FsCtl->pOutputBuffer;
  540. +
  541. +    status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_REQUEST_DELEGATION,
  542. +        &nfs41_srvopen->sec_ctx,
  543. +        pVNetRootContext->session,
  544. +        nfs41_srvopen->nfs41_open_state,
  545. +        pNetRootContext->nfs41d_version,
  546. +        SrvOpen->pAlreadyPrefixedName,
  547. +        &entry);
  548. +    if (status)
  549. +        goto out;
  550. +
  551. +    entry->u.RequestDelegation.requested_type = (ULONG)*input;
  552. +
  553. +    status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
  554. +    if (status) {
  555. +        /* |nfs41_downcall()| owns an abandoned entry */
  556. +        entry = NULL;
  557. +        goto out;
  558. +    }
  559. +
  560. +    if (entry->status != NO_ERROR) {
  561. +        status = map_setfile_error(entry->status);
  562. +        RxContext->CurrentIrp->IoStatus.Status = status;
  563. +        goto out;
  564. +    }
  565. +
  566. +    output->DelegType = (nfs41_open_delegation_type)
  567. +        entry->u.RequestDelegation.deleg_type;
  568. +    output->WhyNoDelegation = (nfs41_why_no_delegation)
  569. +        entry->u.RequestDelegation.why_no_delegation;
  570. +
  571. +    status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
  572. +    RxContext->IoStatusBlock.Information = sizeof(*output);
  573. +out:
  574. +    if (entry)
  575. +        nfs41_UpcallDestroy(entry);
  576. +    return status;
  577. +}
  578. +
  579. +static NTSTATUS nfs41_ReturnDelegation(
  580. +    IN OUT PRX_CONTEXT RxContext)
  581. +{
  582. +    NTSTATUS status;
  583. +    nfs41_updowncall_entry *entry = NULL;
  584. +    PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  585. +    PNFS41_SRV_OPEN nfs41_srvopen = NFS41GetSrvOpenExtension(SrvOpen);
  586. +    PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
  587. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  588. +    PNFS41_NETROOT_EXTENSION pNetRootContext =
  589. +        NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
  590. +    XXCTL_LOWIO_COMPONENT *FsCtl =
  591. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  592. +
  593. +    RxContext->IoStatusBlock.Information = 0;
  594. +
  595. +    if (FsCtl->InputBufferLength != 0)
  596. +        return STATUS_INVALID_PARAMETER;
  597. +
  598. +    status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_RETURN_DELEGATION,
  599. +        &nfs41_srvopen->sec_ctx,
  600. +        pVNetRootContext->session,
  601. +        nfs41_srvopen->nfs41_open_state,
  602. +        pNetRootContext->nfs41d_version,
  603. +        SrvOpen->pAlreadyPrefixedName,
  604. +        &entry);
  605. +    if (status)
  606. +        goto out;
  607. +
  608. +    status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
  609. +    if (status) {
  610. +        /* |nfs41_downcall()| owns an abandoned entry */
  611. +        entry = NULL;
  612. +        goto out;
  613. +    }
  614. +
  615. +    if (entry->status != NO_ERROR) {
  616. +        status = map_setfile_error(entry->status);
  617. +        RxContext->CurrentIrp->IoStatus.Status = status;
  618. +        goto out;
  619. +    }
  620. +
  621. +    status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
  622. +out:
  623. +    if (entry)
  624. +        nfs41_UpcallDestroy(entry);
  625. +    return status;
  626. +}
  627. +
  628. +NTSTATUS marshal_nfs41_requestdelegation(
  629. +    nfs41_updowncall_entry *entry,
  630. +    unsigned char *buf,
  631. +    ULONG buf_len,
  632. +    ULONG *len)
  633. +{
  634. +    NTSTATUS status;
  635. +    ULONG required;
  636. +    unsigned char *tmp = buf;
  637. +
  638. +    status = marshal_nfs41_header(entry, tmp, buf_len, len);
  639. +    if (status)
  640. +        return status;
  641. +    tmp += *len;
  642. +
  643. +    required = *len + sizeof(entry->u.RequestDelegation.requested_type);
  644. +    if (required > buf_len)
  645. +        return STATUS_INSUFFICIENT_RESOURCES;
  646. +
  647. +    UPDOWNCALL_MEMCPY(tmp, &entry->u.RequestDelegation.requested_type,
  648. +        sizeof(entry->u.RequestDelegation.requested_type));
  649. +    tmp += sizeof(entry->u.RequestDelegation.requested_type);
  650. +    *len = (ULONG)(tmp - buf);
  651. +    return STATUS_SUCCESS;
  652. +}
  653. +
  654. +NTSTATUS unmarshal_nfs41_requestdelegation(
  655. +    nfs41_updowncall_entry *cur,
  656. +    const unsigned char *restrict *restrict buf)
  657. +{
  658. +    UPDOWNCALL_MEMCPY(&cur->u.RequestDelegation.deleg_type, *buf,
  659. +        sizeof(cur->u.RequestDelegation.deleg_type));
  660. +    *buf += sizeof(cur->u.RequestDelegation.deleg_type);
  661. +    UPDOWNCALL_MEMCPY(&cur->u.RequestDelegation.why_no_delegation, *buf,
  662. +        sizeof(cur->u.RequestDelegation.why_no_delegation));
  663. +    *buf += sizeof(cur->u.RequestDelegation.why_no_delegation);
  664. +    return STATUS_SUCCESS;
  665. +}
  666. +
  667.  NTSTATUS nfs41_FsCtl(
  668.      IN OUT PRX_CONTEXT RxContext)
  669.  {
  670. @@ -1849,6 +2012,12 @@ NTSTATUS nfs41_FsCtl(
  671.      case FSCTL_NFS41_QUERY_DELEGATION_INFO:
  672.          status = nfs41_QueryDelegationInfo(RxContext);
  673.          break;
  674. +    case FSCTL_NFS41_REQUEST_DELEGATION:
  675. +        status = nfs41_RequestDelegation(RxContext);
  676. +        break;
  677. +    case FSCTL_NFS41_RETURN_DELEGATION:
  678. +        status = nfs41_ReturnDelegation(RxContext);
  679. +        break;
  680.      default:
  681.          break;
  682.      }
  683. diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
  684. index 49c7768..eb81afd 100644
  685. --- a/sys/nfs41sys_updowncall.c
  686. +++ b/sys/nfs41sys_updowncall.c
  687. @@ -320,6 +320,13 @@ NTSTATUS handle_upcall(
  688.          status = marshal_nfs41_querydelegationinfo(entry,
  689.              pbOut, cbOut, len);
  690.          break;
  691. +    case NFS41_SYSOP_FSCTL_REQUEST_DELEGATION:
  692. +        status = marshal_nfs41_requestdelegation(entry,
  693. +            pbOut, cbOut, len);
  694. +        break;
  695. +    case NFS41_SYSOP_FSCTL_RETURN_DELEGATION:
  696. +        status = marshal_nfs41_header(entry, pbOut, cbOut, len);
  697. +        break;
  698.      default:
  699.          status = STATUS_INVALID_PARAMETER;
  700.          print_error("handle_upcall: Unknown nfs41 ops %d\n",
  701. @@ -827,6 +834,10 @@ NTSTATUS nfs41_downcall(
  702.          case NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO:
  703.              unmarshal_nfs41_querydelegationinfo(cur, &inbuf);
  704.              break;
  705. +        case NFS41_SYSOP_FSCTL_REQUEST_DELEGATION:
  706. +            unmarshal_nfs41_requestdelegation(cur, &inbuf);
  707. +            break;
  708. +        case NFS41_SYSOP_FSCTL_RETURN_DELEGATION:
  709.          case NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL:
  710.          case NFS41_SYSOP_SHUTDOWN:
  711.              /* no unmarshal function */
  712. diff --git a/tests/winfsinfo1/winfsinfo.c b/tests/winfsinfo1/winfsinfo.c
  713. index d8859d2..dce3287 100644
  714. --- a/tests/winfsinfo1/winfsinfo.c
  715. +++ b/tests/winfsinfo1/winfsinfo.c
  716. @@ -1974,6 +1974,161 @@ static int fsctlnfs41querydelegationinfo(
  717.      return EXIT_SUCCESS;
  718.  }
  719.  
  720. +static const char *why_no_delegation_name(ULONG why)
  721. +{
  722. +    switch (why) {
  723. +        case NFS41_WND4_NOT_WANTED: return "WND4_NOT_WANTED";
  724. +        case NFS41_WND4_CONTENTION: return "WND4_CONTENTION";
  725. +        case NFS41_WND4_RESOURCE: return "WND4_RESOURCE";
  726. +        case NFS41_WND4_NOT_SUPP_FTYPE: return "WND4_NOT_SUPP_FTYPE";
  727. +        case NFS41_WND4_WRITE_DELEG_NOT_SUPP_FTYPE:
  728. +            return "WND4_WRITE_DELEG_NOT_SUPP_FTYPE";
  729. +        case NFS41_WND4_NOT_SUPP_UPGRADE: return "WND4_NOT_SUPP_UPGRADE";
  730. +        case NFS41_WND4_NOT_SUPP_DOWNGRADE: return "WND4_NOT_SUPP_DOWNGRADE";
  731. +        case NFS41_WND4_CANCELED: return "WND4_CANCELED";
  732. +        case NFS41_WND4_IS_DIR: return "WND4_IS_DIR";
  733. +        default: return NULL;
  734. +    }
  735. +}
  736. +
  737. +static int fsctlnfs41delegationtest(const char *progname,
  738. +    const char *command_list, const char *filename)
  739. +{
  740. +    char *commands;
  741. +    char *saveptr = NULL;
  742. +    char *command;
  743. +    HANDLE hFile;
  744. +    int retval = EXIT_FAILURE;
  745. +    size_t command_list_len;
  746. +    unsigned int command_number = 0;
  747. +
  748. +    command_list_len = strlen(command_list);
  749. +    commands = malloc(command_list_len + 1);
  750. +    if (commands == NULL) {
  751. +        (void)fprintf(stderr, "%s: malloc() failed\n", progname);
  752. +        return EXIT_FAILURE;
  753. +    }
  754. +    (void)memcpy(commands, command_list, command_list_len + 1);
  755. +
  756. +    hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
  757. +        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  758. +        NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  759. +    if (hFile == INVALID_HANDLE_VALUE) {
  760. +        (void)fprintf(stderr, "%s: Error opening file '%s', lasterr=%d\n",
  761. +            progname, filename, (int)GetLastError());
  762. +        free(commands);
  763. +        return EXIT_FAILURE;
  764. +    }
  765. +
  766. +    command = strtok_r(commands, ",", &saveptr);
  767. +    if (command == NULL) {
  768. +        (void)fprintf(stderr, "%s: delegation command list is empty\n",
  769. +            progname);
  770. +        goto out;
  771. +    }
  772. +
  773. +    do {
  774. +        DWORD bytes_returned = 0;
  775. +
  776. +        command_number++;
  777. +        if (!strcmp(command, "requestreaddeleg") ||
  778. +            !strcmp(command, "requestwritedeleg")) {
  779. +            nfs41_open_delegation_type request =
  780. +                !strcmp(command, "requestreaddeleg") ?
  781. +                NFS41_OPEN_DELEGATE_READ : NFS41_OPEN_DELEGATE_WRITE;
  782. +            FILE_NFS41_REQUEST_DELEGATION_RESULT result = { 0 };
  783. +            const char *type_name;
  784. +            const char *why_name = NULL;
  785. +
  786. +            if (!DeviceIoControl(hFile, FSCTL_NFS41_REQUEST_DELEGATION,
  787. +                &request, sizeof(request), &result, sizeof(result),
  788. +                &bytes_returned, NULL)) {
  789. +                (void)fprintf(stderr,
  790. +                    "%s: command %u ('%s'): "
  791. +                    "FSCTL_NFS41_REQUEST_DELEGATION failed, lasterr=%d\n",
  792. +                    progname, command_number, command, (int)GetLastError());
  793. +                goto out;
  794. +            }
  795. +            if (bytes_returned != sizeof(result)) {
  796. +                (void)fprintf(stderr,
  797. +                    "%s: command %u ('%s'): returned %lu bytes, expected %ld\n",
  798. +                    progname, command_number, command, bytes_returned,
  799. +                    (long)sizeof(result));
  800. +                goto out;
  801. +            }
  802. +
  803. +            type_name = delegation_type_name(result.DelegType);
  804. +            if (type_name == NULL) {
  805. +                (void)fprintf(stderr,
  806. +                    "%s: command %u ('%s'): invalid delegation type %lu\n",
  807. +                    progname, command_number, command,
  808. +                    (unsigned long)result.DelegType);
  809. +                goto out;
  810. +            }
  811. +            if (result.DelegType == NFS41_OPEN_DELEGATE_NONE_EXT) {
  812. +                why_name = why_no_delegation_name(result.WhyNoDelegation);
  813. +                if (why_name == NULL) {
  814. +                    (void)fprintf(stderr,
  815. +                        "%s: command %u ('%s'): "
  816. +                        "invalid why_no_delegation4 %lu\n",
  817. +                        progname, command_number, command,
  818. +                        (unsigned long)result.WhyNoDelegation);
  819. +                    goto out;
  820. +                }
  821. +            }
  822. +
  823. +            (void)printf("nfs41_delegation_test_result=(\n"
  824. +                "\tcommand_number=%u\n"
  825. +                "\tcommand='%s'\n"
  826. +                "\tdeleg_type=%lu\n"
  827. +                "\tdeleg_type_name='%s'\n",
  828. +                command_number, command, (unsigned long)result.DelegType,
  829. +                type_name);
  830. +            if (why_name != NULL) {
  831. +                (void)printf("\twhy_no_delegation=%lu\n"
  832. +                    "\twhy_no_delegation_name='%s'\n",
  833. +                    (unsigned long)result.WhyNoDelegation, why_name);
  834. +            }
  835. +            (void)printf(")\n");
  836. +        }
  837. +        else if (!strcmp(command, "returndeleg")) {
  838. +            if (!DeviceIoControl(hFile, FSCTL_NFS41_RETURN_DELEGATION,
  839. +                NULL, 0, NULL, 0, &bytes_returned, NULL)) {
  840. +                (void)fprintf(stderr,
  841. +                    "%s: command %u ('%s'): "
  842. +                    "FSCTL_NFS41_RETURN_DELEGATION failed, lasterr=%d\n",
  843. +                    progname, command_number, command, (int)GetLastError());
  844. +                goto out;
  845. +            }
  846. +            if (bytes_returned != 0) {
  847. +                (void)fprintf(stderr,
  848. +                    "%s: command %u ('%s'): returned %lu bytes, expected 0\n",
  849. +                    progname, command_number, command, bytes_returned);
  850. +                goto out;
  851. +            }
  852. +            (void)printf("nfs41_delegation_test_result=(\n"
  853. +                "\tcommand_number=%u\n"
  854. +                "\tcommand='%s'\n"
  855. +                "\tstatus=success\n"
  856. +                ")\n", command_number, command);
  857. +        }
  858. +        else {
  859. +            (void)fprintf(stderr,
  860. +                "%s: command %u: unknown delegation command '%s'\n",
  861. +                progname, command_number, command);
  862. +            goto out;
  863. +        }
  864. +
  865. +        command = strtok_r(NULL, ",", &saveptr);
  866. +    } while (command != NULL);
  867. +
  868. +    retval = EXIT_SUCCESS;
  869. +out:
  870. +    (void)CloseHandle(hFile);
  871. +    free(commands);
  872. +    return retval;
  873. +}
  874. +
  875.  static
  876.  void usage(void)
  877.  {
  878. @@ -2004,7 +2159,8 @@ void usage(void)
  879.          "get_wnetgetresourceinformation|"
  880.          "get_wnetgetresourceparent|"
  881.          "fsctlnfs41queryidmapinfo|"
  882. -        "fsctlnfs41querydelegationinfo"
  883. +        "fsctlnfs41querydelegationinfo|"
  884. +        "fsctlnfs41delegationtest"
  885.  
  886.          "> args\n");
  887.  }
  888. @@ -2100,8 +2256,23 @@ int main(int ac, char *av[])
  889.          return fsctlnfs41queryidmapinfo(av[0], av[2]);
  890.      }
  891.      else if (!strcmp(subcmd, "fsctlnfs41querydelegationinfo")) {
  892. +        if (ac != 4) {
  893. +            (void)fprintf(stderr, "%s: fsctlnfs41querydelegationinfo "
  894. +                "<read|write|execute|all> filename\n", av[0]);
  895. +            return EXIT_FAILURE;
  896. +        }
  897.          return fsctlnfs41querydelegationinfo(av[0], av[2], av[3]);
  898.      }
  899. +    else if (!strcmp(subcmd, "fsctlnfs41delegationtest")) {
  900. +        if (ac != 4) {
  901. +            (void)fprintf(stderr, "%s: fsctlnfs41delegationtest "
  902. +                "command[,command...] filename\n"
  903. +                "commands: requestreaddeleg, requestwritedeleg, "
  904. +                "returndeleg\n", av[0]);
  905. +            return EXIT_FAILURE;
  906. +        }
  907. +        return fsctlnfs41delegationtest(av[0], av[2], av[3]);
  908. +    }
  909.      else {
  910.          (void)fprintf(stderr, "%s: Unknown subcmd '%s'\n", av[0], subcmd);
  911.          return EXIT_FAILURE;

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