Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp2393428pxb; Thu, 11 Feb 2021 11:09:20 -0800 (PST) X-Google-Smtp-Source: ABdhPJxLbJP7edb83XudASIhd8qnGvgEzn8PDqci75+ALKsdrcnj9vNcSDwISyielJdXBGaNP54R X-Received: by 2002:a50:ec06:: with SMTP id g6mr9777616edr.12.1613070560386; Thu, 11 Feb 2021 11:09:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1613070560; cv=none; d=google.com; s=arc-20160816; b=rmuRajcOK6uV/F0c+Bt92cRgs3aR+kC9IZfvrzqhHkgtiQtruJj225+RvF0yUNlGP9 pg9KcadIer8M7m9NVvdXvWT3XOTg530lXwXCFutMWXeOz74Lnt0NiYCF70A5ZGINmR7y 3Aknp+/D1AyM/S8A6+bvNFPkZYlLT2EO9FDO7X734xuhI1GUmcvQQlOWn9lHTb0PpcRy h7MRuqiKI2x7+Dj5guIYLMLdat9iMLgO3ZjzR4O2jj6dn5W83mTyoCviGvGY3tivnDLx cP1SC/pNmq41/QnIPFJkMAs+XDvY0m7mJ+6e/lmEQszTd3cRlOLJ/PDHLXztKep03PHx 4SXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:from:references :cc:to:subject:dkim-signature; bh=kPhjJXfm6+kQOfWXztpcCTmvFWPa71ZgKqQVo0Ho3dI=; b=RIZ3SgfyBrgWhn2CKD+2PD2dd/XkJCP1BtxH8BGUWATnsD0InOLDBpKn4xyUWAAV7K e/gYY4gVDtjO/Z23oM9twkWivUCX12qJkT8eFYF3MQYs+A7hA5jxWsGJzZJmH6CzqSJm nqEN0434TOHCI4g2wfjVnyr4cj9WNT/SvwSjY3tO1NeuTa3gzv4NFP2qhTB1gjV+ElkB fkMbbkfHqdpzwRzDIgMG8zOLLwQsDig+ToFikKg8E7/jW1yKB8mFQkDD18Nouti0RKpb 8egtMKoEgpvjXKRddwDDo3GMpBZfuWvIS5pEwTTCyWucJCrWZOZ+3gi98lexwtv2qlPN QRbg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=LbEITIm2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f7si5317750edd.595.2021.02.11.11.08.55; Thu, 11 Feb 2021 11:09:20 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=LbEITIm2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231283AbhBKTF0 (ORCPT + 99 others); Thu, 11 Feb 2021 14:05:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229553AbhBKTEM (ORCPT ); Thu, 11 Feb 2021 14:04:12 -0500 Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFBB0C061756; Thu, 11 Feb 2021 11:03:31 -0800 (PST) Received: by mail-ed1-x529.google.com with SMTP id df22so8115783edb.1; Thu, 11 Feb 2021 11:03:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=kPhjJXfm6+kQOfWXztpcCTmvFWPa71ZgKqQVo0Ho3dI=; b=LbEITIm2GF+EoJHZQsnzpUgZgvHIg5RwynEU8X4cKVwcjKRQR2RsxXo51p/+1zFcws QGC+VhHbZ+k6ZZHoC77bPdXNybPWU8F195qO3EuBjlLnkuzC8nuolstUQtygL4yS0wg7 +ybDxAHK92k01MK0Bo6ohfv25/rM7+ZldYlZKYJMIBhiPLC36mhPjjBkcRjYDIEObD9H IFZ0uTiLNCLtJrc818Pq38rMOX5DO7sO+vXaP/x8vMr8paxiexMElapjeFWsi0PVwhNe oPFIEteK+DFnC8XYMYqEczsvsrFKK3gs815OGb4Js0Imr2IEzsnlI8vLf7/bhCbGmSAH u9Vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=kPhjJXfm6+kQOfWXztpcCTmvFWPa71ZgKqQVo0Ho3dI=; b=L5ePyR/t5B/Q0UQbqJMlCtK3hPBMIhYqJ77vUgg+wyifXBZfJrpRi2zM9dw+YSYHJB aQwN7+GDzNsQdAn8PBIwXTP2f6DeqC/v0BD9C/zy27EDNN5c/Jvf5OmybcXygJyptirw SZ8vVC67d1pPw7oKksJ+4/u+HRY0n+uGlvMhdLPWkQzn1ZgYGKVA8CHpE+QuYGKGgYna AfGKS7nh+D0pKp8O6he+QbkMLSAAdrAfQEslCiCwdeMao28fgTjtvpZk5zNLPkHeot2C //6e1406/EnzKZoGo3jr4/b33+hQXdIZB/+bDt9OUme4fvgmJAB9Mqm7ssiQpGkkGifv JvGA== X-Gm-Message-State: AOAM532C6ytSlAPgGGG8GG5swRZbL4NNgI0sxOwK4R6qApHvTVFD3zlb d+AZggVfiBOdIQEH1BIyobT5yP6jN78= X-Received: by 2002:a05:6402:1383:: with SMTP id b3mr9336825edv.131.1613070210543; Thu, 11 Feb 2021 11:03:30 -0800 (PST) Received: from [192.168.178.40] (ipbcc06d06.dynamic.kabel-deutschland.de. [188.192.109.6]) by smtp.gmail.com with ESMTPSA id r23sm5045171ejd.56.2021.02.11.11.03.29 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 11 Feb 2021 11:03:30 -0800 (PST) Subject: Re: [PATCH 1/2] uio: Add late_release callback to uio_info To: Greg Kroah-Hartman Cc: linux-scsi@vger.kernel.org, target-devel@vger.kernel.org, linux-kernel@vger.kernel.org, "Martin K. Petersen" , Mike Christie References: <20210210194031.7422-1-bostroesser@gmail.com> <20210210194031.7422-2-bostroesser@gmail.com> <7bc9eef9-0a9e-58a9-11f1-2c32010c70f0@gmail.com> From: Bodo Stroesser Message-ID: Date: Thu, 11 Feb 2021 20:03:29 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 11.02.21 07:51, Greg Kroah-Hartman wrote: > On Wed, Feb 10, 2021 at 08:57:11PM +0100, Bodo Stroesser wrote: >> On 10.02.21 20:47, Greg Kroah-Hartman wrote: >>> On Wed, Feb 10, 2021 at 08:40:30PM +0100, Bodo Stroesser wrote: >>>> If uio_unregister_device() is called while userspace daemon >>>> still holds the uio device open or mmap'ed, uio will not call >>>> uio_info->release() on later close / munmap. >>>> >>>> At least one user of uio (tcmu) should not free resources (pages >>>> allocated by tcmu which are mmap'ed to userspace) while uio >>>> device still is open, because that could cause userspace daemon >>>> to be killed by SIGSEGV or SIGBUS. Therefore tcmu frees the >>>> pages only after it called uio_unregister_device _and_ the device >>>> was closed. >>>> So, uio not calling uio_info->release causes trouble. >>>> tcmu currently leaks memory in that case. >>>> >>>> Just waiting for userspace daemon to exit before calling >>>> uio_unregister_device I think is not the right solution, because >>>> daemon would not become aware of kernel code wanting to destroy >>>> the uio device. >>>> After uio_unregister_device was called, reading or writing the >>>> uio device returns -EIO, which normally results in daemon exit. >>>> >>>> This patch adds new callback pointer 'late_release' to struct >>>> uio_info. If uio user sets this callback, it will be called by >>>> uio if userspace closes / munmaps the device after >>>> uio_unregister_device was executed. >>>> >>>> That way we can use uio_unregister_device() to notify userspace >>>> that we are going to destroy the device, but still get a call >>>> to late_release when uio device is finally closed. >>>> >>>> Signed-off-by: Bodo Stroesser >>>> --- >>>> Documentation/driver-api/uio-howto.rst | 10 ++++++++++ >>>> drivers/uio/uio.c | 4 ++++ >>>> include/linux/uio_driver.h | 4 ++++ >>>> 3 files changed, 18 insertions(+) >>>> >>>> diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst >>>> index 907ffa3b38f5..a2d57a7d623a 100644 >>>> --- a/Documentation/driver-api/uio-howto.rst >>>> +++ b/Documentation/driver-api/uio-howto.rst >>>> @@ -265,6 +265,16 @@ the members are required, others are optional. >>>> function. The parameter ``irq_on`` will be 0 to disable interrupts >>>> and 1 to enable them. >>>> +- ``int (*late_release)(struct uio_info *info, struct inode *inode)``: >>>> + Optional. If you define your own :c:func:`open()`, you will >>>> + in certain cases also want a custom :c:func:`late_release()` >>>> + function. If uio device is unregistered - by calling >>>> + :c:func:`uio_unregister_device()` - while it is open or mmap'ed by >>>> + userspace, the custom :c:func:`release()` function will not be >>>> + called when userspace later closes the device. An optionally >>>> + specified :c:func:`late_release()` function will be called in that >>>> + situation. >>>> + >>>> Usually, your device will have one or more memory regions that can be >>>> mapped to user space. For each region, you have to set up a >>>> ``struct uio_mem`` in the ``mem[]`` array. Here's a description of the >>>> diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c >>>> index ea96e319c8a0..0b2636f8d373 100644 >>>> --- a/drivers/uio/uio.c >>>> +++ b/drivers/uio/uio.c >>>> @@ -532,6 +532,8 @@ static int uio_release(struct inode *inode, struct file *filep) >>>> mutex_lock(&idev->info_lock); >>>> if (idev->info && idev->info->release) >>>> ret = idev->info->release(idev->info, inode); >>>> + else if (idev->late_info && idev->late_info->late_release) >>>> + ret = idev->late_info->late_release(idev->late_info, inode); >>>> mutex_unlock(&idev->info_lock); >>> >>> Why can't release() be called here? Why doesn't your driver define a >>> release() if it cares about this information? Why do we need 2 >>> different callbacks that fire at exactly the same time? >>> >>> This feels really wrong. >>> >>> greg k-h >>> >> >> tcmu has a release callback. But uio can't call it after >> uio_unregister_device was executed, because in uio_unregister_device >> uio sets the uio_device::info to NULL. > > As it should because the driver could then be gone. It should NEVER > call back into it again. OTOH, uio does try_module_get(idev->owner) in uio_open before calling the driver's open callback and module_put(idev_owner) in uio_release after calling driver's release callback. So driver's release callback is guaranteed to exist until last release is done. Apart from that, tcmu also has an uio_info::mmap callback. In that callback it installs its own vm_operations_struct::fault handler. This handler also can happen to be called as long as userspace holds the uio device mmap'ed. I think, this is not a problem due to the above mentioned mechanism. tcmu just has to ensure, that the tcmu device, which contains the uio_info - is kept until the final release call happens. Unfortunately this call will not happen if uio device is open during uio_unregister_device. That's why tcmu sometimes leaks memory. > >> So, uio would never call both callbacks for the same release action, >> but would call release before uio_unregister_device is executed, and >> late_release after that. > > That's not ok. > >> Of course it would be good for tcmu if uio would call uio_info:release even >> after uio_unregister_device, but changing this AFAICS could cause >> trouble in other drivers using uio. > > You are confusing two different lifetime rules here it seems. One is > the char device and one is the struct device. They work independently > as different users affect them. I'm not sure I get your point. > > So if one is removed from the system, do not try to keep a callback to > it, otherwise you will crash. That's why I tried to change uio in a compatible way, so other drivers based on it are not afflicted by the change. I saw, that some drivers based on uio free their resources directly after calling uio_unregister_device. Executing their release callback later would definitely cause trouble. > > And why is scsi using the uio driver in the first place? That feels > really odd to me. Why not just make a "real" driver if you want to > somehow tie these two lifetimes together? Why tcmu driver is based on uio I don't know. I inherited the driver as it is. Maybe it would have been better to not base it on uio, I don't know. But changing this now would cause an API change for all existing userspace apps, e.g. tcmu-runner. I think I should avoid that and therefore have to find an acceptable solution for the tcmu/uio combination. > > thanks, > > greg k-h >