@@ -266,12 +266,18 @@ static void expkey_flush(void)
266266 mutex_unlock (& nfsd_mutex );
267267}
268268
269+ static int expkey_notify (struct cache_detail * cd , struct cache_head * h )
270+ {
271+ return nfsd_cache_notify (cd , h , NFSD_CACHE_TYPE_EXPKEY );
272+ }
273+
269274static const struct cache_detail svc_expkey_cache_template = {
270275 .owner = THIS_MODULE ,
271276 .hash_size = EXPKEY_HASHMAX ,
272277 .name = "nfsd.fh" ,
273278 .cache_put = expkey_put ,
274279 .cache_upcall = expkey_upcall ,
280+ .cache_notify = expkey_notify ,
275281 .cache_request = expkey_request ,
276282 .cache_parse = expkey_parse ,
277283 .cache_show = expkey_show ,
@@ -322,6 +328,266 @@ svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
322328 return NULL ;
323329}
324330
331+ /**
332+ * nfsd_nl_expkey_get_reqs_dumpit - dump pending expkey requests
333+ * @skb: reply buffer
334+ * @cb: netlink metadata and command arguments
335+ *
336+ * Walk the expkey cache's pending request list and create a netlink
337+ * message with a nested entry for each cache_request, containing the
338+ * seqno, client string, fsidtype and fsid.
339+ *
340+ * Uses cb->args[0] as a seqno cursor for dump continuation across
341+ * multiple netlink messages.
342+ *
343+ * Returns the size of the reply or a negative errno.
344+ */
345+ int nfsd_nl_expkey_get_reqs_dumpit (struct sk_buff * skb ,
346+ struct netlink_callback * cb )
347+ {
348+ struct nfsd_net * nn ;
349+ struct cache_detail * cd ;
350+ struct cache_head * * items ;
351+ u64 * seqnos ;
352+ int cnt , i , emitted ;
353+ void * hdr ;
354+ int ret ;
355+
356+ nn = net_generic (sock_net (skb -> sk ), nfsd_net_id );
357+
358+ mutex_lock (& nfsd_mutex );
359+
360+ cd = nn -> svc_expkey_cache ;
361+ if (!cd ) {
362+ ret = - ENODEV ;
363+ goto out_unlock ;
364+ }
365+
366+ cnt = sunrpc_cache_requests_count (cd );
367+ if (!cnt ) {
368+ ret = 0 ;
369+ goto out_unlock ;
370+ }
371+
372+ items = kcalloc (cnt , sizeof (* items ), GFP_KERNEL );
373+ seqnos = kcalloc (cnt , sizeof (* seqnos ), GFP_KERNEL );
374+ if (!items || !seqnos ) {
375+ ret = - ENOMEM ;
376+ goto out_alloc ;
377+ }
378+
379+ cnt = sunrpc_cache_requests_snapshot (cd , items , seqnos , cnt ,
380+ cb -> args [0 ]);
381+ if (!cnt ) {
382+ ret = 0 ;
383+ goto out_alloc ;
384+ }
385+
386+ hdr = genlmsg_put (skb , NETLINK_CB (cb -> skb ).portid ,
387+ cb -> nlh -> nlmsg_seq , & nfsd_nl_family ,
388+ NLM_F_MULTI , NFSD_CMD_EXPKEY_GET_REQS );
389+ if (!hdr ) {
390+ ret = - ENOBUFS ;
391+ goto out_put ;
392+ }
393+
394+ emitted = 0 ;
395+ for (i = 0 ; i < cnt ; i ++ ) {
396+ struct svc_expkey * ek ;
397+ struct nlattr * nest ;
398+
399+ ek = container_of (items [i ], struct svc_expkey , h );
400+
401+ nest = nla_nest_start (skb , NFSD_A_EXPKEY_REQS_REQUESTS );
402+ if (!nest )
403+ break ;
404+
405+ if (nla_put_u64_64bit (skb , NFSD_A_EXPKEY_SEQNO ,
406+ seqnos [i ], 0 ) ||
407+ nla_put_string (skb , NFSD_A_EXPKEY_CLIENT ,
408+ ek -> ek_client -> name ) ||
409+ nla_put_u8 (skb , NFSD_A_EXPKEY_FSIDTYPE ,
410+ ek -> ek_fsidtype ) ||
411+ nla_put (skb , NFSD_A_EXPKEY_FSID ,
412+ key_len (ek -> ek_fsidtype ), ek -> ek_fsid )) {
413+ nla_nest_cancel (skb , nest );
414+ break ;
415+ }
416+
417+ nla_nest_end (skb , nest );
418+ cb -> args [0 ] = seqnos [i ];
419+ emitted ++ ;
420+ }
421+
422+ if (!emitted ) {
423+ genlmsg_cancel (skb , hdr );
424+ ret = - EMSGSIZE ;
425+ goto out_put ;
426+ }
427+
428+ genlmsg_end (skb , hdr );
429+ ret = skb -> len ;
430+ out_put :
431+ for (i = 0 ; i < cnt ; i ++ )
432+ cache_put (items [i ], cd );
433+ out_alloc :
434+ kfree (seqnos );
435+ kfree (items );
436+ out_unlock :
437+ mutex_unlock (& nfsd_mutex );
438+ return ret ;
439+ }
440+
441+ /**
442+ * nfsd_nl_parse_one_expkey - parse one expkey entry from netlink
443+ * @cd: cache_detail for the expkey cache
444+ * @attr: nested attribute containing expkey fields
445+ *
446+ * Parses one expkey entry from a netlink message and updates the
447+ * cache. Mirrors the logic in expkey_parse().
448+ *
449+ * Returns 0 on success or a negative errno.
450+ */
451+ static int nfsd_nl_parse_one_expkey (struct cache_detail * cd ,
452+ struct nlattr * attr )
453+ {
454+ struct nlattr * tb [NFSD_A_EXPKEY_PATH + 1 ];
455+ struct auth_domain * dom = NULL ;
456+ struct svc_expkey key ;
457+ struct svc_expkey * ek = NULL ;
458+ struct timespec64 boot ;
459+ int err ;
460+ u8 fsidtype ;
461+ int fsid_len ;
462+
463+ err = nla_parse_nested (tb , NFSD_A_EXPKEY_PATH , attr ,
464+ nfsd_expkey_nl_policy , NULL );
465+ if (err )
466+ return err ;
467+
468+ /* client (required) */
469+ if (!tb [NFSD_A_EXPKEY_CLIENT ])
470+ return - EINVAL ;
471+
472+ dom = auth_domain_find (nla_data (tb [NFSD_A_EXPKEY_CLIENT ]));
473+ if (!dom )
474+ return - ENOENT ;
475+
476+ /* fsidtype (required) */
477+ if (!tb [NFSD_A_EXPKEY_FSIDTYPE ]) {
478+ err = - EINVAL ;
479+ goto out_dom ;
480+ }
481+ fsidtype = nla_get_u8 (tb [NFSD_A_EXPKEY_FSIDTYPE ]);
482+ if (key_len (fsidtype ) == 0 ) {
483+ err = - EINVAL ;
484+ goto out_dom ;
485+ }
486+
487+ /* fsid (required) */
488+ if (!tb [NFSD_A_EXPKEY_FSID ]) {
489+ err = - EINVAL ;
490+ goto out_dom ;
491+ }
492+ fsid_len = nla_len (tb [NFSD_A_EXPKEY_FSID ]);
493+ if (fsid_len != key_len (fsidtype )) {
494+ err = - EINVAL ;
495+ goto out_dom ;
496+ }
497+
498+ /* expiry (required, wallclock seconds) */
499+ if (!tb [NFSD_A_EXPKEY_EXPIRY ]) {
500+ err = - EINVAL ;
501+ goto out_dom ;
502+ }
503+
504+ key .h .flags = 0 ;
505+ getboottime64 (& boot );
506+ key .h .expiry_time = nla_get_u64 (tb [NFSD_A_EXPKEY_EXPIRY ]) -
507+ boot .tv_sec ;
508+ key .ek_client = dom ;
509+ key .ek_fsidtype = fsidtype ;
510+ memcpy (key .ek_fsid , nla_data (tb [NFSD_A_EXPKEY_FSID ]), fsid_len );
511+
512+ ek = svc_expkey_lookup (cd , & key );
513+ if (!ek ) {
514+ err = - ENOMEM ;
515+ goto out_dom ;
516+ }
517+
518+ if (tb [NFSD_A_EXPKEY_NEGATIVE ]) {
519+ set_bit (CACHE_NEGATIVE , & key .h .flags );
520+ ek = svc_expkey_update (cd , & key , ek );
521+ if (ek )
522+ trace_nfsd_expkey_update (ek , NULL );
523+ else
524+ err = - ENOMEM ;
525+ } else if (tb [NFSD_A_EXPKEY_PATH ]) {
526+ err = kern_path (nla_data (tb [NFSD_A_EXPKEY_PATH ]), 0 ,
527+ & key .ek_path );
528+ if (err )
529+ goto out_ek ;
530+ ek = svc_expkey_update (cd , & key , ek );
531+ if (ek )
532+ trace_nfsd_expkey_update (ek ,
533+ nla_data (tb [NFSD_A_EXPKEY_PATH ]));
534+ else
535+ err = - ENOMEM ;
536+ path_put (& key .ek_path );
537+ } else {
538+ err = - EINVAL ;
539+ goto out_ek ;
540+ }
541+
542+ cache_flush ();
543+
544+ out_ek :
545+ if (ek )
546+ cache_put (& ek -> h , cd );
547+ out_dom :
548+ auth_domain_put (dom );
549+ return err ;
550+ }
551+
552+ /**
553+ * nfsd_nl_expkey_set_reqs_doit - respond to expkey requests
554+ * @skb: reply buffer
555+ * @info: netlink metadata and command arguments
556+ *
557+ * Parse one or more expkey cache responses from userspace and
558+ * update the expkey cache accordingly.
559+ *
560+ * Returns 0 on success or a negative errno.
561+ */
562+ int nfsd_nl_expkey_set_reqs_doit (struct sk_buff * skb ,
563+ struct genl_info * info )
564+ {
565+ struct nfsd_net * nn ;
566+ struct cache_detail * cd ;
567+ const struct nlattr * attr ;
568+ int rem , ret = 0 ;
569+
570+ nn = net_generic (genl_info_net (info ), nfsd_net_id );
571+
572+ mutex_lock (& nfsd_mutex );
573+
574+ cd = nn -> svc_expkey_cache ;
575+ if (!cd ) {
576+ ret = - ENODEV ;
577+ goto out_unlock ;
578+ }
579+
580+ nlmsg_for_each_attr_type (attr , NFSD_A_EXPKEY_REQS_REQUESTS ,
581+ info -> nlhdr , GENL_HDRLEN , rem ) {
582+ ret = nfsd_nl_parse_one_expkey (cd , (struct nlattr * )attr );
583+ if (ret )
584+ break ;
585+ }
586+
587+ out_unlock :
588+ mutex_unlock (& nfsd_mutex );
589+ return ret ;
590+ }
325591
326592#define EXPORT_HASHBITS 8
327593#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
0 commit comments