From patchwork Tue Feb 28 16:57:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 9596419 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0F55060453 for ; Tue, 28 Feb 2017 17:41:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0594E25223 for ; Tue, 28 Feb 2017 17:41:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EE57228159; Tue, 28 Feb 2017 17:41:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B53E225223 for ; Tue, 28 Feb 2017 17:41:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750957AbdB1Rld (ORCPT ); Tue, 28 Feb 2017 12:41:33 -0500 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:42781 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751332AbdB1Rl3 (ORCPT ); Tue, 28 Feb 2017 12:41:29 -0500 Received: from pps.filterd (m0044012.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v1SGnhhF027863; Tue, 28 Feb 2017 08:58:05 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=M8JBMbDrPDgllbIsQa9M96fcBZJAbTYFVamlxT6j9nw=; b=YJflAkW4YAKiydH1Hxavj15moUDSRPOpdJNHuzHAfaTvX33JaYTHsYEpa2y0DPzlnqWK 5+0pEQhDKjqCwEK4S3jBStAVKGY/RDpJRJPvov77CpvlGbtfYr5aM741fRdwztZfTA5F hdIuNwMIENQIY04xX4wQvy8r843uAWTEOuw= Received: from maileast.thefacebook.com ([199.201.65.23]) by mx0a-00082601.pphosted.com with ESMTP id 28w769scfn-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Tue, 28 Feb 2017 08:58:05 -0800 Received: from NAM02-CY1-obe.outbound.protection.outlook.com (192.168.183.28) by o365-in.thefacebook.com (192.168.177.23) with Microsoft SMTP Server (TLS) id 14.3.319.2; Tue, 28 Feb 2017 11:58:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.onmicrosoft.com; s=selector1-fb-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=M8JBMbDrPDgllbIsQa9M96fcBZJAbTYFVamlxT6j9nw=; b=cmj0P85tQxbrD+ce/jD8gvPSApZh6EEMFK8LnIjA3QaKOdFdmqEwz3zRWeWoZLGubRUnoe47eHQjqNfkneotaZbM1arwhnj+At1EUGwABby4/OHrFdtFddscWX+fSLi+YGNWZ9nZ6GDdCtoGO0g5iJJobOl9xdlTKCaCfwCSaZo= Received: from localhost (2606:a000:4381:1201:225:22ff:feb3:e51a) by CY4PR15MB1911.namprd15.prod.outlook.com (10.174.54.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.933.12; Tue, 28 Feb 2017 16:57:44 +0000 From: Josef Bacik To: , , , Subject: [PATCH 2/6] nbd: ref count the nbd device Date: Tue, 28 Feb 2017 11:57:07 -0500 Message-ID: <1488301031-3199-3-git-send-email-jbacik@fb.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488301031-3199-1-git-send-email-jbacik@fb.com> References: <1488301031-3199-1-git-send-email-jbacik@fb.com> MIME-Version: 1.0 X-Originating-IP: [2606:a000:4381:1201:225:22ff:feb3:e51a] X-ClientProxiedBy: BN6PR11CA0030.namprd11.prod.outlook.com (10.173.25.16) To CY4PR15MB1911.namprd15.prod.outlook.com (10.174.54.144) X-MS-Office365-Filtering-Correlation-Id: 8e1dcb56-0a0d-4e45-d85b-08d45ffaea58 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:CY4PR15MB1911; X-Microsoft-Exchange-Diagnostics: 1; CY4PR15MB1911; 3:h8KxU8C65AiBI9Z+p/CSUpxXwwxT+f9VGM+IUglSPqVdddq75+vO0ZnM516Rh6TcjOtmxTR7KVGbc6l/HQ6G5ORlEnH+LHr4JfDhkJMYVEulOBG7gcNqw3FcyNuduJdUsg/6nk3GBzqaNrytKzpcYT8eZYcSOajKEbFMo1bZ8lFZP7nMXhPsAn/4S62cWAPrGVGBS/kiH38W3pvJVLgF7ASmm8I3ylH8ZOTngNIhbinuE2t8k8Ky86wBvVEt+jzk0JME9B/JNkaO5ehmYEx9yA==; 25:nNMx5EghKwAqhzNrtRwD53xKL0ZFOg+0mKQz38jNSyu5XhRWcT28+cJeFX3kKBorJVrb+q8rPyOhL2xswDcIlaFdEZYGz0mB7dMyvPsVAVDyiH1FLvDdXoSqGzDM4B1KhBLt+ilh5RzclH7WI5FsGtDGB8HSt9esu9nT2jKVllwxH8MUQZd+RENIRybKS1e8J/igbSpeL3opxRift9+BAGXzU226TSx8FC9JOOeXcV2M4xRAfffc+GEbDzlxD/DPTno/1+f0LqPelvem9UB/JEYFWxaVlf9iiCGWXY5rj29e+tRPcyoL7s4DDYL73qhAvgVgDQAU/BVVPz7OD265E1HXAV/P434DIRiaEHfemM3WoaBa4CmOr7ytRZkyr7fg0SKhTSOjH5q4XV9XfTFu39bGxHY4/cuQuyjoIu21dS/8nOPfK65YwiMSJw0n9y7K X-Microsoft-Exchange-Diagnostics: 1; CY4PR15MB1911; 31:g79lBzu/F7+HMJHwfjjGRKO57sUZHN2gQTVWo4sKHa1pP14ZysxUBdAIykQD1thWq9LGcYr0r1qYElW4s3DVfZXjHGAfatrqS1bURDGEe7SsgceGt+vgzeLZA+lCF/XIJg394abj4BOYSrbFWkjJzIceR3KczSX+2xOC0O5qiHHmEEEDHJNJaVXdIGfva8mtzanWPMvP+vQ01zYri8ncFoSF9oU9/2/v53S4Bjw01vw=; 20:qlSDalKrVLvGCnumq9+RIndoniRXX46gg4OP1AovT6/TiNKw+uahFcqs0JBWWuvTyYAOaBFnZV113FqzUz5hBKFNdftngIDJbllF9FdzxG14ei4ZQCLw+6UtEvam2fCzZAKHlsKtzfF/GVjz10SN84CCEFjye1nh1vZxj8uxFd69+SQ5XwUdWt3utzzUPoOKEz+vU4c/3TjR45szTU0g4iYMcxMk8X+2nbGghatWGAQKWYLAu6UZMWu1qf8VSjUQStgkyMt/EN0pfSTuFWktmTWNmxlzJwXwxmJpLbImbronPWgArF3/E6KK56QY/7zTJlPRy5AAFg78GmNaugGHNe41UhSx60D5UScllGeYX8+SaUl+2Yd3o1bNH00HRvJTD5tv+3e9gnqShxbmsqAJoA6Dgw6+U0TgTUYxt2I0VjT4getcSsvupotvXP1VXRfBWiCWeBQPRAuEmTpSCUJfRub4VLXSaMbycqtEZvaE0lOYOfkDJ9B6pw/Rjdo42ADI X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(158342451672863)(67672495146484); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040375)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6041248)(20161123558025)(20161123564025)(20161123562025)(20161123555025)(20161123560025)(6072148); SRVR:CY4PR15MB1911; BCL:0; PCL:0; RULEID:; SRVR:CY4PR15MB1911; X-Microsoft-Exchange-Diagnostics: 1; CY4PR15MB1911; 4:BIC8j8gTaDalsGRWVwdLXbZc+clggwE016GgJ7Y4c2l0QSAnjW5ZIY8aTzG1wT+UvMTfmUukNJ6Bm+cunN753UpMAhXunCCrwulLBkHvqy0pJcG9Lis2/74oqb5AUpWljxOu/1D5Y7O+WQtsGhKeQG/0ZYeRN5o1GRoWD7+eLNbkq63gW3u9Z4CPmn1NHETr2Bde8aXX9y/+253SHlK1Ol35uM5ta6IL+7SicQfzhau7U8L+4oLNkDExhixAe8pTkaTgM6AjKAGIBWuNv8IwV0NcuMLkUboV5lKTLPmkr19TclrsKjFGJx7xn5TcLeHdzeEMIra1JotasT2VD1mvbKPkXoEVOgzBvyh/CKJ5QOhPTbJ5Aq43Bsu4qwt+NWmkOKD9y79LuxLD8bpraRRQFEo5q0Wu1zgcIRyD4a3mpF0flq+Q8lQDVTst0iwbhiZL/exHucGr1fvSFIN74P2kOAgzVYMT2nRhbnmzMViXl+mwU3RVUg0anUatSScCQLIlddwf9qMsqSc43PXdZTrcY71bw3YtwVcT1inKhyMs8trrbo2UU5O3ZkmkBjA5QFSEIYzkluKIRESQjhAAq3uBczIOc2zjPXdqsXiKxva1JHacotv8AIYi/Ff1JvMxAIDqsQ/r1DnimPyYx6ENbFsYzIBdAH44P9xI6iuFO3eh5QCAlyjq2UMJcxUBiuDQMpG6 X-Forefront-PRVS: 0232B30BBC X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6069001)(6009001)(7916002)(39450400003)(39410400002)(39830400002)(199003)(45904002)(189002)(50226002)(189998001)(97736004)(36756003)(47776003)(2201001)(38730400002)(5003940100001)(48376002)(50466002)(42186005)(92566002)(86362001)(53936002)(6496005)(76506005)(2906002)(6666003)(6116002)(305945005)(6486002)(7736002)(105586002)(2950100002)(6636002)(101416001)(5660300001)(50986999)(68736007)(76176999)(25786008)(81166006)(33646002)(81156014)(8676002)(106356001); DIR:OUT; SFP:1102; SCL:1; SRVR:CY4PR15MB1911; H:localhost; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: fb.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY4PR15MB1911; 23:oes4ohzJNh6O324E82EwXlQU4hQdxB5HYJmhj7b5R?= =?us-ascii?Q?94xRmh59BaMLL1R/DMcHJkBOrntqQXi7nGCkWMa2NpNrDdFo+dU6+3P3xpbo?= =?us-ascii?Q?wkFsL/MHH1cTSEpUYKSSmcaiLnU1+lbbbTe+ck4HGHiM0xcspUtcZ3OjeCjJ?= =?us-ascii?Q?Oi0Ev2nSwOrSSJroZqJzOZpx6SWVHO3MlNptqaL0cckKW/j36ao5TXt8FW6I?= =?us-ascii?Q?QK2CQMIULCN5nM7W5AXcjzFJfruH/CgCv+wkEGHcgH5NfSzoQB+bFz5HPgIx?= =?us-ascii?Q?YO5puUxoko+O3PhEdSKf3Y9ifKL0p7+PvmlCjkPRXRpdYL4ZSyKj69RxNmKj?= =?us-ascii?Q?UgBOcI2QFZPlv4XVpfrSjzl9eSGrm/CxdecOK48AAlOFPu/HF58qfM68VusX?= =?us-ascii?Q?LFqYrSmASeJrH9Ix1LC8r+SAt0lLQj33FfUJRhn7Av0hFmhnPd73TJanb5Pj?= =?us-ascii?Q?SIpb3pvADyGnyqQ9lzmH7EKN9LE9c59MMWJ9CV9XtlwcMRuQVl7cV1jMUiK/?= =?us-ascii?Q?NzCIosVsc28AY8g0gVi7iBuNAmJIC6BJXIgcck+1H2oRSU2cUBic1UYqbC/L?= =?us-ascii?Q?80s5qfvQZknfVdydQQEhNBCNhMP9UPEwTHOCW8qoByXaAcL/k6rAih1KQ0qW?= =?us-ascii?Q?QKLjI0whHpbrdZxiW5/r+rSn/ftAtUFh/mL+WxXh+QnC8IwUFaLETINSwFDa?= =?us-ascii?Q?/xGt0kilkrMwH18902YxtMVi6bHkIPPqfR8svw6IsCDF25ikFc/VXXqy/KSh?= =?us-ascii?Q?DrOymN8NfFM8wlXXuGKI9pxZubXDbcOjOQi0B9fKptb6wQQRUE1YZlQ3w0it?= =?us-ascii?Q?G4C4AU6EX8ulTytdGZQ2lnZbvVyNOO05rWSlpF+AVVfje1r+131GrPhaHA84?= =?us-ascii?Q?W71IXmK9fq/IiiBc4URRRf5c/mIwvSGfBMcziuZ/SJ7adLiR5gEVcurwZ0Sk?= =?us-ascii?Q?admOUjY9nPnOeN39yMgAZeDl2Sxw5hB3kUpuwuC8xRb+dpb8tK9EY2Ji8pOl?= =?us-ascii?Q?6QWxgrTfLOziRtMXGsQ4UfzRFAGnH0fwZcq6aSxztmsaUFC47xAcvWGhwjd8?= =?us-ascii?Q?p65l00mACRvGYtC1b+D+7NzULH8+TxnEXaq9iuCv5YbpVgCSEJA8ulJtU3RG?= =?us-ascii?Q?fjJyBvt6vOTNtnqo3cImWW0UbDrMPrO?= X-Microsoft-Exchange-Diagnostics: 1; CY4PR15MB1911; 6:hqvFNFl9Oixod2HYt3v+zX5Jeqo3WTzanr3rkG3twSs2gd2+WUrPKt6DdD8xPMLGV4G0JWDHVZHQ3LZKstM4RW+HBBqeXApPt8NvWULrXmPsot0jTqXXpm2fEcTBo5277mvu8/aEzLcOk08nxBNgaR2sEelGCG5eSW9hwsFheJWt/HzFoj5mGUXqMFsYzzYuNxigWSup4NMfvGSu3Hr0oI1V3tzMg9HOFo47JzUMHdVSQSWXEsBOB+BLTxxeLQypkQ8apRVs5mdXVhaEgesZDhvweQZQjBtoJozXt2srcxEIXKlfnnSrkjxZ9fTlUs9T4kDNGQIoAZrA3z/RKeQMU/BlzYuLqxR7a63AVsoWCxmQz1iMCuxSg+k1Maw+cJhbGsVnok47ldJkLXbRuL+mUw==; 5:29h1wxW/Fie1eScwSL+dDW6sQGEhgCOUerloPT38sUASqFpHM2+sYY8WSTL0DTIlVdFjoId8lgUUMLkVYeCAjoY57rQj9FJ8/RbBTXsioMUYyTdtnzq/Pfxlq1SHY8CwUeIBn1rhDRVvsk9MvRLADAH+6Y1zyyNyT1UjMKAet8w=; 24:uHOwc2K2rmsw/Esli3q5T9/Xb3fnFslzGSBw76Mgd/Fpp5DewWKsn0CAJFCnMTFmcJZ/g85gVqNDhQl4xNVLy1z8dkyzLgi+lNH59kxD7ZQ= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; CY4PR15MB1911; 7:8xA2xwLsAWUili6jDvNzaS0GvBHY+B1iRpj3rpoSObkmvNMgE2eoqhx0LLieltYRYOD3ryPW98Smb4Qs1gFWT3Pagz6i+SoJB2fRVFbzwR5Hbz3y+wB6YRXpH5D7hsFuiLs4VQyg5g0Eydmv8X7xVGDew8lu5sK8VD8Tv/3mxgXeccAIlB/TUCa4Nn36CugKk72OWmZDqfxJEogiol9SDYBRpCZXPPGpPxv9STV+97Ny4guiaPht1SN+cDs4yaUPoMmOjgIOIMn6SOuIcFRV1qubgJYCth9IFAFSBHahOhHAp/8QL9zPaDwBdNATSYcQQtJs48RBz0lEOWYEZbbZoA==; 20:QKj9jfacDF3J7UucpaVotGQNdeE7Uk4YGFTALoLCgWAV6cKnFXjqymW67SjSk5qqMerXHBAh7VY5t/2D6WWimpjnZv8T3G1D6gP7LKwoEKkLbLl7nev00fkKQl0D9Oc6jgixzDZftLbcZPKl+O16xBvv9yL0mE4PAWPBpEtaGFM= X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Feb 2017 16:57:44.2048 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR15MB1911 X-OriginatorOrg: fb.com X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-02-28_15:, , signatures=0 Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In preparation for seamless reconnects and the netlink configuration interface we need a way to make sure our nbd device configuration doesn't disappear until we are finished with it. So add a ref counter, and on the final put we do all of the cleanup work on the nbd device. At configuration time we only allow a device to be configured if it's ref count is currently 0. Signed-off-by: Josef Bacik --- drivers/block/nbd.c | 210 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 133 insertions(+), 77 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 7a91c8f..6760ee5 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -51,22 +51,33 @@ struct nbd_sock { int fallback_index; }; +struct recv_thread_args { + struct work_struct work; + struct nbd_device *nbd; + int index; +}; + #define NBD_TIMEDOUT 0 #define NBD_DISCONNECT_REQUESTED 1 #define NBD_DISCONNECTED 2 -#define NBD_RUNNING 3 +#define NBD_HAS_SOCKS_REF 3 struct nbd_device { u32 flags; unsigned long runtime_flags; + struct nbd_sock **socks; + atomic_t refs; + wait_queue_head_t socks_wq; + int num_connections; + + struct recv_thread_args *args; int magic; struct blk_mq_tag_set tag_set; struct mutex config_lock; struct gendisk *disk; - int num_connections; atomic_t recv_threads; wait_queue_head_t recv_wq; loff_t blksize; @@ -101,7 +112,7 @@ static int part_shift; static int nbd_dev_dbg_init(struct nbd_device *nbd); static void nbd_dev_dbg_close(struct nbd_device *nbd); - +static void nbd_put(struct nbd_device *nbd); static inline struct device *nbd_to_dev(struct nbd_device *nbd) { @@ -125,6 +136,25 @@ static const char *nbdcmd_to_ascii(int cmd) return "invalid"; } +static ssize_t pid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + struct nbd_device *nbd = (struct nbd_device *)disk->private_data; + + return sprintf(buf, "%d\n", task_pid_nr(nbd->task_recv)); +} + +static struct device_attribute pid_attr = { + .attr = { .name = "pid", .mode = S_IRUGO}, + .show = pid_show, +}; + +static int nbd_get_unless_zero(struct nbd_device *nbd) +{ + return atomic_add_unless(&nbd->refs, 1, 0); +} + static int nbd_size_clear(struct nbd_device *nbd, struct block_device *bdev) { bd_set_size(bdev, 0); @@ -181,6 +211,7 @@ static void sock_shutdown(struct nbd_device *nbd) mutex_lock(&nsock->tx_lock); kernel_sock_shutdown(nsock->sock, SHUT_RDWR); mutex_unlock(&nsock->tx_lock); + nsock->dead = true; } dev_warn(disk_to_dev(nbd->disk), "shutting down sockets\n"); } @@ -191,10 +222,14 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req); struct nbd_device *nbd = cmd->nbd; + if (!nbd_get_unless_zero(nbd)) { + req->errors++; + return BLK_EH_HANDLED; + } + if (nbd->num_connections > 1) { dev_err_ratelimited(nbd_to_dev(nbd), "Connection timed out, retrying\n"); - mutex_lock(&nbd->config_lock); /* * Hooray we have more connections, requeue this IO, the submit * path will put it on a real connection. @@ -208,21 +243,19 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, kernel_sock_shutdown(nsock->sock, SHUT_RDWR); mutex_unlock(&nsock->tx_lock); } - mutex_unlock(&nbd->config_lock); blk_mq_requeue_request(req, true); + nbd_put(nbd); return BLK_EH_RESET_TIMER; } - mutex_unlock(&nbd->config_lock); } else { dev_err_ratelimited(nbd_to_dev(nbd), "Connection timed out\n"); } set_bit(NBD_TIMEDOUT, &nbd->runtime_flags); req->errors++; - - mutex_lock(&nbd->config_lock); sock_shutdown(nbd); - mutex_unlock(&nbd->config_lock); + nbd_put(nbd); + return BLK_EH_HANDLED; } @@ -474,26 +507,6 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) return cmd; } -static ssize_t pid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - struct nbd_device *nbd = (struct nbd_device *)disk->private_data; - - return sprintf(buf, "%d\n", task_pid_nr(nbd->task_recv)); -} - -static struct device_attribute pid_attr = { - .attr = { .name = "pid", .mode = S_IRUGO}, - .show = pid_show, -}; - -struct recv_thread_args { - struct work_struct work; - struct nbd_device *nbd; - int index; -}; - static void recv_work(struct work_struct *work) { struct recv_thread_args *args = container_of(work, @@ -516,6 +529,7 @@ static void recv_work(struct work_struct *work) } atomic_dec(&nbd->recv_threads); wake_up(&nbd->recv_wq); + nbd_put(nbd); } static void nbd_clear_req(struct request *req, void *data, bool reserved) @@ -589,9 +603,16 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) struct nbd_sock *nsock; int ret; + if (!nbd_get_unless_zero(nbd)) { + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Socks array is empty\n"); + return -EINVAL; + } + if (index >= nbd->num_connections) { dev_err_ratelimited(disk_to_dev(nbd->disk), "Attempted send on invalid socket\n"); + nbd_put(nbd); return -EINVAL; } req->errors = 0; @@ -599,8 +620,10 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) nsock = nbd->socks[index]; if (nsock->dead) { index = find_fallback(nbd, index); - if (index < 0) + if (index < 0) { + nbd_put(nbd); return -EIO; + } nsock = nbd->socks[index]; } @@ -618,7 +641,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) goto again; } mutex_unlock(&nsock->tx_lock); - + nbd_put(nbd); return ret; } @@ -659,21 +682,27 @@ static int nbd_add_socket(struct nbd_device *nbd, struct block_device *bdev, if (!sock) return err; - if (!nbd->task_setup) + err = -EINVAL; + if (!nbd->task_setup && !atomic_cmpxchg(&nbd->refs, 0, 1)) { nbd->task_setup = current; + set_bit(NBD_HAS_SOCKS_REF, &nbd->runtime_flags); + try_module_get(THIS_MODULE); + } + if (nbd->task_setup != current) { dev_err(disk_to_dev(nbd->disk), "Device being setup by another task"); - return -EINVAL; + goto out; } + err = -ENOMEM; socks = krealloc(nbd->socks, (nbd->num_connections + 1) * sizeof(struct nbd_sock *), GFP_KERNEL); if (!socks) - return -ENOMEM; + goto out; nsock = kzalloc(sizeof(struct nbd_sock), GFP_KERNEL); if (!nsock) - return -ENOMEM; + goto out; nbd->socks = socks; @@ -685,7 +714,9 @@ static int nbd_add_socket(struct nbd_device *nbd, struct block_device *bdev, if (max_part) bdev->bd_invalidated = 1; - return 0; + err = 0; +out: + return err; } /* Reset all properties of an NBD device */ @@ -697,6 +728,7 @@ static void nbd_reset(struct nbd_device *nbd) set_capacity(nbd->disk, 0); nbd->flags = 0; nbd->tag_set.timeout = 0; + nbd->args = NULL; queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue); } @@ -741,20 +773,17 @@ static void send_disconnects(struct nbd_device *nbd) static int nbd_disconnect(struct nbd_device *nbd, struct block_device *bdev) { dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n"); - if (!nbd->socks) + if (!nbd_get_unless_zero(nbd)) return -EINVAL; mutex_unlock(&nbd->config_lock); fsync_bdev(bdev); mutex_lock(&nbd->config_lock); - /* Check again after getting mutex back. */ - if (!nbd->socks) - return -EINVAL; - if (!test_and_set_bit(NBD_DISCONNECT_REQUESTED, &nbd->runtime_flags)) send_disconnects(nbd); + nbd_put(nbd); return 0; } @@ -764,49 +793,74 @@ static int nbd_clear_sock(struct nbd_device *nbd, struct block_device *bdev) nbd_clear_que(nbd); kill_bdev(bdev); nbd_bdev_reset(bdev); - /* - * We want to give the run thread a chance to wait for everybody - * to clean up and then do it's own cleanup. - */ - if (!test_bit(NBD_RUNNING, &nbd->runtime_flags) && - nbd->num_connections) { - int i; - - for (i = 0; i < nbd->num_connections; i++) - kfree(nbd->socks[i]); - kfree(nbd->socks); - nbd->socks = NULL; - nbd->num_connections = 0; - } nbd->task_setup = NULL; - + if (test_and_clear_bit(NBD_HAS_SOCKS_REF, &nbd->runtime_flags)) + nbd_put(nbd); return 0; } +static void nbd_put(struct nbd_device *nbd) +{ + if (atomic_dec_and_test(&nbd->refs)) { + struct block_device *bdev; + + bdev = bdget_disk(nbd->disk, 0); + if (!bdev) + return; + + mutex_lock(&nbd->config_lock); + nbd_dev_dbg_close(nbd); + nbd_size_clear(nbd, bdev); + device_remove_file(disk_to_dev(nbd->disk), &pid_attr); + nbd->task_recv = NULL; + nbd_clear_sock(nbd, bdev); + if (nbd->num_connections) { + int i; + for (i = 0; i < nbd->num_connections; i++) + kfree(nbd->socks[i]); + kfree(nbd->socks); + nbd->num_connections = 0; + nbd->socks = NULL; + } + kfree(nbd->args); + nbd_reset(nbd); + mutex_unlock(&nbd->config_lock); + bdput(bdev); + module_put(THIS_MODULE); + } +} + static int nbd_start_device(struct nbd_device *nbd, struct block_device *bdev) { struct recv_thread_args *args; int num_connections = nbd->num_connections; int error = 0, i; - if (nbd->task_recv) - return -EBUSY; - if (!nbd->socks) + if (!nbd_get_unless_zero(nbd)) return -EINVAL; + if (nbd->task_recv) { + error = -EBUSY; + goto out; + } + if (!nbd->socks) { + error = -EINVAL; + goto out; + } + if (num_connections > 1 && !(nbd->flags & NBD_FLAG_CAN_MULTI_CONN)) { dev_err(disk_to_dev(nbd->disk), "server does not support multiple connections per device.\n"); error = -EINVAL; - goto out_err; + goto out; } - set_bit(NBD_RUNNING, &nbd->runtime_flags); blk_mq_update_nr_hw_queues(&nbd->tag_set, nbd->num_connections); args = kcalloc(num_connections, sizeof(*args), GFP_KERNEL); if (!args) { error = -ENOMEM; - goto out_err; + goto out; } + nbd->args = args; nbd->task_recv = current; mutex_unlock(&nbd->config_lock); @@ -815,7 +869,7 @@ static int nbd_start_device(struct nbd_device *nbd, struct block_device *bdev) error = device_create_file(disk_to_dev(nbd->disk), &pid_attr); if (error) { dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n"); - goto out_recv; + goto out; } nbd_size_update(nbd, bdev); @@ -824,32 +878,26 @@ static int nbd_start_device(struct nbd_device *nbd, struct block_device *bdev) for (i = 0; i < num_connections; i++) { sk_set_memalloc(nbd->socks[i]->sock->sk); atomic_inc(&nbd->recv_threads); + atomic_inc(&nbd->refs); INIT_WORK(&args[i].work, recv_work); args[i].nbd = nbd; args[i].index = i; queue_work(recv_workqueue, &args[i].work); } - wait_event_interruptible(nbd->recv_wq, - atomic_read(&nbd->recv_threads) == 0); + error = wait_event_interruptible(nbd->recv_wq, + atomic_read(&nbd->recv_threads) == 0); + if (error) + sock_shutdown(nbd); for (i = 0; i < num_connections; i++) flush_work(&args[i].work); - nbd_dev_dbg_close(nbd); - nbd_size_clear(nbd, bdev); - device_remove_file(disk_to_dev(nbd->disk), &pid_attr); -out_recv: mutex_lock(&nbd->config_lock); - nbd->task_recv = NULL; -out_err: - clear_bit(NBD_RUNNING, &nbd->runtime_flags); - nbd_clear_sock(nbd, bdev); - +out: /* user requested, ignore socket errors */ if (test_bit(NBD_DISCONNECT_REQUESTED, &nbd->runtime_flags)) error = 0; if (test_bit(NBD_TIMEDOUT, &nbd->runtime_flags)) error = -ETIMEDOUT; - - nbd_reset(nbd); + nbd_put(nbd); return error; } @@ -905,16 +953,21 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, { struct nbd_device *nbd = bdev->bd_disk->private_data; int error; + bool need_put = false; if (!capable(CAP_SYS_ADMIN)) return -EPERM; BUG_ON(nbd->magic != NBD_MAGIC); + /* This is to keep us from doing the final put under the config_lock. */ + if (nbd_get_unless_zero(nbd)) + need_put = true; mutex_lock(&nbd->config_lock); error = __nbd_ioctl(bdev, nbd, cmd, arg); mutex_unlock(&nbd->config_lock); - + if (need_put) + nbd_put(nbd); return error; } @@ -1141,12 +1194,15 @@ static int nbd_dev_add(int index) nbd->magic = NBD_MAGIC; mutex_init(&nbd->config_lock); + atomic_set(&nbd->refs, 0); + nbd->args = NULL; disk->major = NBD_MAJOR; disk->first_minor = index << part_shift; disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index); init_waitqueue_head(&nbd->recv_wq); + init_waitqueue_head(&nbd->socks_wq); nbd_reset(nbd); add_disk(disk); return index;