From patchwork Mon Nov 12 20:00:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 1730211 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 434BD3FCAE for ; Mon, 12 Nov 2012 20:01:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752663Ab2KLUBJ (ORCPT ); Mon, 12 Nov 2012 15:01:09 -0500 Received: from mail-vc0-f174.google.com ([209.85.220.174]:61244 "EHLO mail-vc0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752395Ab2KLUBI (ORCPT ); Mon, 12 Nov 2012 15:01:08 -0500 Received: by mail-vc0-f174.google.com with SMTP id fk26so6536725vcb.19 for ; Mon, 12 Nov 2012 12:01:07 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=Vj5ysIwYAPUnYpUTgZOYhO0eiLCxctzMxUIBvnIOVkc=; b=Y413bJ4RKEzQUeu3Tg2D5kXyHEjq0VVlducnh3808RiX6aqclgsN5XSHb4PpirurtY UmPNyJESrIoTswLmq8YEhQXJSfcS78fbkeF2lf2GvnC83kyIifb41z6zXB1zMEzlnsZT 1fsI9hAr97F0/AF3e+dYj7QGVpW6mZJRdkv4T4Plwf/vBeZVJt1YY9aktxL2xsWxEjqd bK0GV8EIMi6lhT8MsRnxZhASGCymrGDX4elnwkutHYDUqHP+qCymD1sEiIT83/PsqV/R ZAIUbbAysWDdM+AEJPyXSxpQhSoGpxWbttuN40a8I4XpOXtkGJWexjsxizPsR1WFJSc5 /NDQ== Received: by 10.220.157.15 with SMTP id z15mr1822162vcw.38.1352750466929; Mon, 12 Nov 2012 12:01:06 -0800 (PST) Received: from salusa.poochiereds.net (cpe-107-015-110-129.nc.res.rr.com. [107.15.110.129]) by mx.google.com with ESMTPS id dh10sm7390369veb.8.2012.11.12.12.01.05 (version=SSLv3 cipher=OTHER); Mon, 12 Nov 2012 12:01:05 -0800 (PST) From: Jeff Layton To: bfields@fieldses.org Cc: linux-nfs@vger.kernel.org Subject: [PATCH 01/11] nfsd: add a usermodehelper upcall for NFSv4 client ID tracking Date: Mon, 12 Nov 2012 15:00:48 -0500 Message-Id: <1352750458-16857-2-git-send-email-jlayton@redhat.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1352750458-16857-1-git-send-email-jlayton@redhat.com> References: <1352750458-16857-1-git-send-email-jlayton@redhat.com> X-Gm-Message-State: ALoCoQlYXiz9LdYYs5ysTS7OttqfBREr0d03MFStZGmBJVzNKDNdqUCUfXFTRYB2nYIei/RkOH7V Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Add a new client tracker upcall type that uses call_usermodehelper to call out to a program. This seems to be the preferred method of calling out to usermode these days for seldom-called upcalls. It's simple and doesn't require a running daemon, so it should "just work" as long as the binary is installed. The client tracking exit operation is also changed to check for a NULL pointer before running. The UMH upcall doesn't need to do anything at module teardown time. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4recover.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 151921b..2fc2f6c 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -927,6 +927,137 @@ static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { .grace_done = nfsd4_cld_grace_done, }; +/* upcall via usermodehelper */ +static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack"; +module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog), + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program"); + +static int +nfsd4_umh_cltrack_upcall(char *cmd, char *arg) +{ + char *envp[] = { NULL }; + char *argv[4]; + int ret; + + if (unlikely(!cltrack_prog[0])) { + dprintk("%s: cltrack_prog is disabled\n", __func__); + return -EACCES; + } + + dprintk("%s: cmd: %s\n", __func__, cmd); + dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)"); + + argv[0] = (char *)cltrack_prog; + argv[1] = cmd; + argv[2] = arg; + argv[3] = NULL; + + ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); + /* + * Disable the upcall mechanism if we're getting an ENOENT or EACCES + * error. The admin can re-enable it on the fly by using sysfs + * once the problem has been fixed. + */ + if (ret == -ENOENT || ret == -EACCES) { + dprintk("NFSD: %s was not found or isn't executable (%d). " + "Setting cltrack_prog to blank string!", + cltrack_prog, ret); + cltrack_prog[0] = '\0'; + } + dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret); + + return ret; +} + +static char * +bin_to_hex_dup(const unsigned char *src, int srclen) +{ + int i; + char *buf, *hex; + + /* +1 for terminating NULL */ + buf = kmalloc((srclen * 2) + 1, GFP_KERNEL); + if (!buf) + return buf; + + hex = buf; + for (i = 0; i < srclen; i++) { + sprintf(hex, "%2.2x", *src++); + hex += 2; + } + return buf; +} + +static int +nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net) +{ + return nfsd4_umh_cltrack_upcall("init", NULL); +} + +static void +nfsd4_umh_cltrack_create(struct nfs4_client *clp) +{ + char *hexid; + + hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); + if (!hexid) { + dprintk("%s: can't allocate memory for upcall!\n", __func__); + return; + } + nfsd4_umh_cltrack_upcall("create", hexid); + kfree(hexid); +} + +static void +nfsd4_umh_cltrack_remove(struct nfs4_client *clp) +{ + char *hexid; + + hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); + if (!hexid) { + dprintk("%s: can't allocate memory for upcall!\n", __func__); + return; + } + nfsd4_umh_cltrack_upcall("remove", hexid); + kfree(hexid); +} + +static int +nfsd4_umh_cltrack_check(struct nfs4_client *clp) +{ + int ret; + char *hexid; + + hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); + if (!hexid) { + dprintk("%s: can't allocate memory for upcall!\n", __func__); + return -ENOMEM; + } + ret = nfsd4_umh_cltrack_upcall("check", hexid); + kfree(hexid); + return ret; +} + +static void +nfsd4_umh_cltrack_grace_done(struct net __attribute__((unused)) *net, + time_t boot_time) +{ + char timestr[22]; /* FIXME: better way to determine max size? */ + + sprintf(timestr, "%ld", boot_time); + nfsd4_umh_cltrack_upcall("gracedone", timestr); +} + +static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { + .init = nfsd4_umh_cltrack_init, + .exit = NULL, + .create = nfsd4_umh_cltrack_create, + .remove = nfsd4_umh_cltrack_remove, + .check = nfsd4_umh_cltrack_check, + .grace_done = nfsd4_umh_cltrack_grace_done, +}; + int nfsd4_client_tracking_init(struct net *net) { @@ -957,7 +1088,8 @@ void nfsd4_client_tracking_exit(struct net *net) { if (client_tracking_ops) { - client_tracking_ops->exit(net); + if (client_tracking_ops->exit) + client_tracking_ops->exit(net); client_tracking_ops = NULL; } }