Message ID | CAGudoHGqRr_WNz86pmgK9Kmnwsox+_XXqqbp+rLW53e5t8higg@mail.gmail.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c44e:0:b0:3f2:4152:657d with SMTP id w14csp2242016vqr; Tue, 8 Aug 2023 09:35:17 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGEnJM0PELuqWzZb9KEa3BUe1clOm/F9yQaT8+jHsLK3o/2C3wSmhM1hLfsOJ5uVfqKUD4W X-Received: by 2002:a17:902:ea0f:b0:1bb:d045:ae8 with SMTP id s15-20020a170902ea0f00b001bbd0450ae8mr197869plg.7.1691512517029; Tue, 08 Aug 2023 09:35:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691512517; cv=none; d=google.com; s=arc-20160816; b=ZCdEL3iWEi4Xn3o5RnKy8igWKtvfqU4bcft0DyFx//jOV880IT1p1VeHHZxrtRgce3 JoQV/fGnWVbyY+DJDBiUpritvBkcKrzVz6TGcqnSlrl+iX19q+fF6FD3AW4L6p1Z7zkd dI0/yLYlrVhtqRH/QWOuuy1ON94IqwhyxBdd7pKfLjb35YxVfckNS2rrI0PkEVV5zcn6 rYVMeDvaBR0+UPHTZt6aoVe/mFsw7lbsk1m4TSKVRPJONbKjqGTJNEDk3mvOAMyNGGF3 +y08URtz1nhXq1eMEzLTo3qLiJVIhiU+w7aY6LRaFaWdlN6HZ+cax6qaK63Lu4sA5PNf uTwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:references :in-reply-to:mime-version:dkim-signature; bh=6UZdpxVqC4w8SgYwxIIci9xl2Bf47JDQV85VclFbqpI=; fh=YX72GWvnC0SinfzsjaevgOFQuHGMkRxIQgwI7RgHPro=; b=mhoD77UKhCmvamz02mXdFK1JOeS6zRQMtF6KskQAXRHBd7J9mEWJeCrbLWL0VPbAaO ial0e6REgJEhc1Nt7byoSOBuTDoTipTDAMKzhJL/6GNciV+7Rr6Nk3Q5AOTFetn/FqQY Qw/OkbbZAayGv8NQwBRDgulnOJSo5KH39fR7JKl/KZpNxnCpz3p+V4G9Il1ji5VWWASH KCsS+aUqsegfSmYCTj3h+UteSVaM3FfmPVvTtZsoOPDfyTM1VyclDxQ4pjnIdFXj3phq 0Scs6fffxmEKyI85fEHlQyrMB5WCcBlXqPT6/Zd/KnmpnEpr9FmCLK+ayfJnjVYYr+IG 9THQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20221208 header.b=DX05ZENr; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id n13-20020a170903110d00b001b896086ca1si7751894plh.136.2023.08.08.09.34.59; Tue, 08 Aug 2023 09:35:17 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20221208 header.b=DX05ZENr; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 S230367AbjHHPxo (ORCPT <rfc822;aaronkmseo@gmail.com> + 99 others); Tue, 8 Aug 2023 11:53:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56998 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230288AbjHHPv7 (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 8 Aug 2023 11:51:59 -0400 Received: from mail-ua1-f54.google.com (mail-ua1-f54.google.com [209.85.222.54]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C347E5246; Tue, 8 Aug 2023 08:42:53 -0700 (PDT) Received: by mail-ua1-f54.google.com with SMTP id a1e0cc1a2514c-79aeb0a4665so1606925241.1; Tue, 08 Aug 2023 08:42:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1691509026; x=1692113826; h=cc:to:subject:message-id:date:from:references:in-reply-to :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=6UZdpxVqC4w8SgYwxIIci9xl2Bf47JDQV85VclFbqpI=; b=DX05ZENrxsPC/aV+iC0MNe7iC17rhR7d//ZdC/DNe+CI9XBzA08O5aEVkpJ/oXRCdE MCFPv1qbb2Fu9V+Be+1YiMon3Lcfc6fVcCTonrk69jJtccvDnnNBFdarsc43UZ7igo3T phf8H8WQpO0CfgtzFUnAlTxlykTSAva3e9q9qjZbQ7PCPSrZvhOYYiKK3wAt+uDZw2OV WgDcz9Z6yvZG7zR2AS9G8jGhl8eKDVv9JeAlIEUV0/fw99iQquAxSADGBtCJyeQixSrv Iu+61fnFId9kIA3pXWrQdMHv15x21aIh5rDPE4Q4x6HAA1uECeW/khJ3F6kEWZFFYYCM 3Q+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1691509026; x=1692113826; h=cc:to:subject:message-id:date:from:references:in-reply-to :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=6UZdpxVqC4w8SgYwxIIci9xl2Bf47JDQV85VclFbqpI=; b=GYp7BtaLovUp7CzNt8XQRE9Bi4EGMZ86WYBEA2zO4n0yxRsBDnKhF9fhv0swEi0nDL 835W6nzf2nrPSArF/8dzQ4LDJjGoXqzNAn4i7C+yns7UCjQmqdJBdyWBkpGhVoTUy0OY 2SbwXRUkUol2nJSPUTiCgMxbDjYeZw1JBA7+0bE28bKg85/HZkXm4AADiZM75ZF5nL10 wGWivsDbMgKNNcatvZb6f6sZAxgecx7KixX+jkc2WF2UF7qcRd/N/3hgkU4jZPfYjKbf phqr75+6bwkmehMc0JzecOqf+CCj2QrL5+lDGF93tZpW7woU5uYiI06mP+QCJWz4ATZa f8yw== X-Gm-Message-State: AOJu0YzASlnRz58/Xe2apPkZYzaom3405HQqyX6eketLKC4aKV7GC4nW hpDmKOKJBh9JPcy033nHe0M6Kum3Wxqbi4EnnrxA0fKciVs= X-Received: by 2002:a4a:918b:0:b0:56d:10bb:c2d2 with SMTP id d11-20020a4a918b000000b0056d10bbc2d2mr180377ooh.0.1691507243556; Tue, 08 Aug 2023 08:07:23 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a8a:696:0:b0:4f0:1250:dd51 with HTTP; Tue, 8 Aug 2023 08:07:22 -0700 (PDT) In-Reply-To: <CAGudoHEQ6Tq=88VKqurypjHqOzfU2eBmPts4+H8C7iNu96MRKQ@mail.gmail.com> References: <20230806230627.1394689-1-mjguzik@gmail.com> <87o7jidqlg.fsf@email.froward.int.ebiederm.org> <20230808-eingaben-lumpen-e3d227386e23@brauner> <CAGudoHF=cEvXy3v96dN_ruXHnPv33BA6fA+dCWCm-9L3xgMPNQ@mail.gmail.com> <20230808-unsensibel-scham-c61a71622ae7@brauner> <CAGudoHEQ6Tq=88VKqurypjHqOzfU2eBmPts4+H8C7iNu96MRKQ@mail.gmail.com> From: Mateusz Guzik <mjguzik@gmail.com> Date: Tue, 8 Aug 2023 17:07:22 +0200 Message-ID: <CAGudoHGqRr_WNz86pmgK9Kmnwsox+_XXqqbp+rLW53e5t8higg@mail.gmail.com> Subject: [PATCH v2 (kindof)] fs: use __fput_sync in close(2) To: Christian Brauner <brauner@kernel.org> Cc: "Eric W. Biederman" <ebiederm@xmission.com>, viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, oleg@redhat.com, Matthew Wilcox <willy@infradead.org>, Linus Torvalds <torvalds@linux-foundation.org> Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773526120003775878 X-GMAIL-MSGID: 1773679428698933057 |
Series |
[v2,(kindof)] fs: use __fput_sync in close(2)
|
|
Commit Message
Mateusz Guzik
Aug. 8, 2023, 3:07 p.m. UTC
I slapped the following variant just for illustration purposes. - adds __close_fd which returns a struct file - adds __filp_close with a flag whether to fput - makes close(2) use both - transparent to everyone else Downside is that __fput_sync still loses the assert. Instead of losing, it could perhaps be extended with a hack to check syscall number -- pass if either this is close (or binary compat close) or a kthread, BUG out otherwise. Alternatively perhaps deref could be opencoded along with a comment about real fput that this is taking place. Or maybe some other cosmetic choice. I cannot compile-test right now, so down below is a rough copy make sure it is clear what I mean. I feel compelled to note that simple patches get microbenchmarked all the time, with these results being the only justification provided. I'm confused why this patch is supposed to be an exception given its simplicity. Serious justification should be expected from tough calls -- complicated, invasive changes, maybe with numerous tradeoffs. In contrast close(2) doing __fput_sync looks a clear cut thing to do, at worst one can argue which way to do it. extern struct filename *getname_uflags(const char __user *, int);
Comments
On Tue, Aug 08, 2023 at 05:07:22PM +0200, Mateusz Guzik wrote: > I slapped the following variant just for illustration purposes. > > - adds __close_fd which returns a struct file > - adds __filp_close with a flag whether to fput > - makes close(2) use both > - transparent to everyone else > > Downside is that __fput_sync still loses the assert. Instead of > losing, it could perhaps be extended with a hack to check syscall > number -- pass if either this is close (or binary compat close) or a > kthread, BUG out otherwise. Alternatively perhaps deref could be > opencoded along with a comment about real fput that this is taking > place. Or maybe some other cosmetic choice. > > I cannot compile-test right now, so down below is a rough copy make > sure it is clear what I mean. > > I feel compelled to note that simple patches get microbenchmarked all > the time, with these results being the only justification provided. > I'm confused why this patch is supposed to be an exception given its > simplicity. > > Serious justification should be expected from tough calls -- > complicated, invasive changes, maybe with numerous tradeoffs. > > In contrast close(2) doing __fput_sync looks a clear cut thing to do, > at worst one can argue which way to do it. > > diff --git a/fs/file.c b/fs/file.c > index 3fd003a8604f..c341b07533b0 100644 > --- a/fs/file.c > +++ b/fs/file.c > @@ -651,20 +651,30 @@ static struct file *pick_file(struct > files_struct *files, unsigned fd) > return file; > } > > -int close_fd(unsigned fd) > +struct file *__close_fd(unsigned fd, struct file_struct *files) > { > - struct files_struct *files = current->files; > struct file *file; > > spin_lock(&files->file_lock); > file = pick_file(files, fd); > spin_unlock(&files->file_lock); > + > + return file; > +} > +EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ > + > +int close_fd(unsigned fd) > +{ > + struct files_struct *files = current->files; > + struct file *file; > + > + file = __close_fd(fd, files); > if (!file) > return -EBADF; > > return filp_close(file, files); > } > -EXPORT_SYMBOL(close_fd); /* for ksys_close() */ > +EXPORT_SYMBOL(close_fd); > > /** > * last_fd - return last valid index into fd table > diff --git a/fs/file_table.c b/fs/file_table.c > index fc7d677ff5ad..b7461f0b73f4 100644 > --- a/fs/file_table.c > +++ b/fs/file_table.c > @@ -463,6 +463,11 @@ void __fput_sync(struct file *file) > { > if (atomic_long_dec_and_test(&file->f_count)) { > struct task_struct *task = current; > + /* > + * I see 2 basic options > + * 1. just remove the assert > + * 2. demand the flag *or* that the caller is close(2) > + */ > BUG_ON(!(task->flags & PF_KTHREAD)); > __fput(file); > } > diff --git a/fs/open.c b/fs/open.c > index e6ead0f19964..b1602307c1c3 100644 > --- a/fs/open.c > +++ b/fs/open.c > @@ -1533,7 +1533,16 @@ EXPORT_SYMBOL(filp_close); > */ > SYSCALL_DEFINE1(close, unsigned int, fd) > { > - int retval = close_fd(fd); > + struct files_struct *files = current->files; > + struct file *file; > + int retval; > + > + file = __close_fd(fd); > + if (!file) > + return -EBADF; > + > + retval = __filp_close(file, files, false); > + __fput_sync(file); > > /* can't restart close syscall because file table entry was cleared */ > if (unlikely(retval == -ERESTARTSYS || > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 562f2623c9c9..e64c0238a65f 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2388,7 +2388,11 @@ static inline struct file > *file_clone_open(struct file *file) > { > return dentry_open(&file->f_path, file->f_flags, file->f_cred); > } > -extern int filp_close(struct file *, fl_owner_t id); > +extern int __filp_close(struct file *file, fl_owner_t id, bool dofput); > +static inline int filp_close(struct file *file, fl_owner_t id) > +{ > + return __filp_close(file, id, true); > +} > > extern struct filename *getname_flags(const char __user *, int, int *); > extern struct filename *getname_uflags(const char __user *, int); At least make this really dumb and obvious and keep the ugliness to internal.h and open.c --- fs/file_table.c | 10 ++++++++++ fs/internal.h | 1 + fs/open.c | 21 +++++++++++++++------ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/fs/file_table.c b/fs/file_table.c index fc7d677ff5ad..18f8adaba972 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -471,6 +471,16 @@ void __fput_sync(struct file *file) EXPORT_SYMBOL(fput); EXPORT_SYMBOL(__fput_sync); +/* + * Same as __fput_sync() but for regular close. + * Not exported, not for general use. + */ +void fput_sync(struct file *file) +{ + if (atomic_long_dec_and_test(&file->f_count)) + __fput(file); +} + void __init files_init(void) { filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, diff --git a/fs/internal.h b/fs/internal.h index f7a3dc111026..1ad2a4ce728b 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -297,6 +297,7 @@ static inline ssize_t do_get_acl(struct mnt_idmap *idmap, #endif ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *pos); +void fput_sync(struct file *file); /* * fs/attr.c diff --git a/fs/open.c b/fs/open.c index e6ead0f19964..2540b22fb114 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1499,11 +1499,7 @@ SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode) } #endif -/* - * "id" is the POSIX thread ID. We use the - * files pointer for this.. - */ -int filp_close(struct file *filp, fl_owner_t id) +static int __filp_close(struct file *filp, fl_owner_t id, bool may_delay) { int retval = 0; @@ -1520,10 +1516,23 @@ int filp_close(struct file *filp, fl_owner_t id) dnotify_flush(filp, id); locks_remove_posix(filp, id); } - fput(filp); + + if (may_delay) + fput(filp); + else + fput_sync(filp); return retval; } +/* + * "id" is the POSIX thread ID. We use the + * files pointer for this.. + */ +int filp_close(struct file *filp, fl_owner_t id) +{ + return __filp_close(filp, id, true); +} + EXPORT_SYMBOL(filp_close); /*
On Tue, Aug 08, 2023 at 06:30:06PM +0200, Christian Brauner wrote: > On Tue, Aug 08, 2023 at 05:07:22PM +0200, Mateusz Guzik wrote: > > I slapped the following variant just for illustration purposes. > > > > - adds __close_fd which returns a struct file > > - adds __filp_close with a flag whether to fput > > - makes close(2) use both > > - transparent to everyone else > > > > Downside is that __fput_sync still loses the assert. Instead of > > losing, it could perhaps be extended with a hack to check syscall > > number -- pass if either this is close (or binary compat close) or a > > kthread, BUG out otherwise. Alternatively perhaps deref could be > > opencoded along with a comment about real fput that this is taking > > place. Or maybe some other cosmetic choice. > > > > I cannot compile-test right now, so down below is a rough copy make > > sure it is clear what I mean. > > > > I feel compelled to note that simple patches get microbenchmarked all > > the time, with these results being the only justification provided. > > I'm confused why this patch is supposed to be an exception given its > > simplicity. > > > > Serious justification should be expected from tough calls -- > > complicated, invasive changes, maybe with numerous tradeoffs. > > > > In contrast close(2) doing __fput_sync looks a clear cut thing to do, > > at worst one can argue which way to do it. > > > > diff --git a/fs/file.c b/fs/file.c > > index 3fd003a8604f..c341b07533b0 100644 > > --- a/fs/file.c > > +++ b/fs/file.c > > @@ -651,20 +651,30 @@ static struct file *pick_file(struct > > files_struct *files, unsigned fd) > > return file; > > } > > > > -int close_fd(unsigned fd) > > +struct file *__close_fd(unsigned fd, struct file_struct *files) > > { > > - struct files_struct *files = current->files; > > struct file *file; > > > > spin_lock(&files->file_lock); > > file = pick_file(files, fd); > > spin_unlock(&files->file_lock); > > + > > + return file; > > +} > > +EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ > > + > > +int close_fd(unsigned fd) > > +{ > > + struct files_struct *files = current->files; > > + struct file *file; > > + > > + file = __close_fd(fd, files); > > if (!file) > > return -EBADF; > > > > return filp_close(file, files); > > } > > -EXPORT_SYMBOL(close_fd); /* for ksys_close() */ > > +EXPORT_SYMBOL(close_fd); > > > > /** > > * last_fd - return last valid index into fd table > > diff --git a/fs/file_table.c b/fs/file_table.c > > index fc7d677ff5ad..b7461f0b73f4 100644 > > --- a/fs/file_table.c > > +++ b/fs/file_table.c > > @@ -463,6 +463,11 @@ void __fput_sync(struct file *file) > > { > > if (atomic_long_dec_and_test(&file->f_count)) { > > struct task_struct *task = current; > > + /* > > + * I see 2 basic options > > + * 1. just remove the assert > > + * 2. demand the flag *or* that the caller is close(2) > > + */ > > BUG_ON(!(task->flags & PF_KTHREAD)); > > __fput(file); > > } > > diff --git a/fs/open.c b/fs/open.c > > index e6ead0f19964..b1602307c1c3 100644 > > --- a/fs/open.c > > +++ b/fs/open.c > > @@ -1533,7 +1533,16 @@ EXPORT_SYMBOL(filp_close); > > */ > > SYSCALL_DEFINE1(close, unsigned int, fd) > > { > > - int retval = close_fd(fd); > > + struct files_struct *files = current->files; > > + struct file *file; > > + int retval; > > + > > + file = __close_fd(fd); > > + if (!file) > > + return -EBADF; > > + > > + retval = __filp_close(file, files, false); > > + __fput_sync(file); > > > > /* can't restart close syscall because file table entry was cleared */ > > if (unlikely(retval == -ERESTARTSYS || > > diff --git a/include/linux/fs.h b/include/linux/fs.h > > index 562f2623c9c9..e64c0238a65f 100644 > > --- a/include/linux/fs.h > > +++ b/include/linux/fs.h > > @@ -2388,7 +2388,11 @@ static inline struct file > > *file_clone_open(struct file *file) > > { > > return dentry_open(&file->f_path, file->f_flags, file->f_cred); > > } > > -extern int filp_close(struct file *, fl_owner_t id); > > +extern int __filp_close(struct file *file, fl_owner_t id, bool dofput); > > +static inline int filp_close(struct file *file, fl_owner_t id) > > +{ > > + return __filp_close(file, id, true); > > +} > > > > extern struct filename *getname_flags(const char __user *, int, int *); > > extern struct filename *getname_uflags(const char __user *, int); > > At least make this really dumb and obvious and keep the ugliness to > internal.h and open.c Sorry, I only sent a portion of the patch...
On Tue, 8 Aug 2023 at 09:30, Christian Brauner <brauner@kernel.org> wrote: > > At least make this really dumb and obvious and keep the ugliness to > internal.h and open.c See the patch I just sent out. I hate yours too, for that nasty "bool may_delay". I hate those "bool flag" things that change behavior of a function. It may be obvious when you look at the function itself, and know the code, but then it causes things like this: return __filp_close(filp, id, true); and there is zero clue about what the heck 'true' means. At least then the "behavior flags" are named bitmasks, things make *sense*. But we have too many of these boolean arguments. And yes, I realize that we have tons of extant ones, and this would be only one more in a sea of others. That doesn't make it ok. So please keep it to when it *has* to be done to avoid major problems. Linus
On Tue, Aug 08, 2023 at 10:05:20AM -0700, Linus Torvalds wrote: > On Tue, 8 Aug 2023 at 09:30, Christian Brauner <brauner@kernel.org> wrote: > > > > At least make this really dumb and obvious and keep the ugliness to > > internal.h and open.c > > See the patch I just sent out. Yeah, I saw.
From: Linus Torvalds > Sent: 08 August 2023 18:05 ... > return __filp_close(filp, id, true); > > and there is zero clue about what the heck 'true' means. > > At least then the "behavior flags" are named bitmasks, things make > *sense*. But we have too many of these boolean arguments. And make the usual case 0. I was chasing through some code that has a flag for a conditional lock. However is was 'NEED_TO_LOCK' not 'ALREADY_LOCKED'. (bpf calling in with the socket locked). As well as making the code harder to read it is an accident just waiting to happen. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
diff --git a/fs/file.c b/fs/file.c index 3fd003a8604f..c341b07533b0 100644 --- a/fs/file.c +++ b/fs/file.c @@ -651,20 +651,30 @@ static struct file *pick_file(struct files_struct *files, unsigned fd) return file; } -int close_fd(unsigned fd) +struct file *__close_fd(unsigned fd, struct file_struct *files) { - struct files_struct *files = current->files; struct file *file; spin_lock(&files->file_lock); file = pick_file(files, fd); spin_unlock(&files->file_lock); + + return file; +} +EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ + +int close_fd(unsigned fd) +{ + struct files_struct *files = current->files; + struct file *file; + + file = __close_fd(fd, files); if (!file) return -EBADF; return filp_close(file, files); } -EXPORT_SYMBOL(close_fd); /* for ksys_close() */ +EXPORT_SYMBOL(close_fd); /** * last_fd - return last valid index into fd table diff --git a/fs/file_table.c b/fs/file_table.c index fc7d677ff5ad..b7461f0b73f4 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -463,6 +463,11 @@ void __fput_sync(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; + /* + * I see 2 basic options + * 1. just remove the assert + * 2. demand the flag *or* that the caller is close(2) + */ BUG_ON(!(task->flags & PF_KTHREAD)); __fput(file); } diff --git a/fs/open.c b/fs/open.c index e6ead0f19964..b1602307c1c3 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1533,7 +1533,16 @@ EXPORT_SYMBOL(filp_close); */ SYSCALL_DEFINE1(close, unsigned int, fd) { - int retval = close_fd(fd); + struct files_struct *files = current->files; + struct file *file; + int retval; + + file = __close_fd(fd); + if (!file) + return -EBADF; + + retval = __filp_close(file, files, false); + __fput_sync(file); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || diff --git a/include/linux/fs.h b/include/linux/fs.h index 562f2623c9c9..e64c0238a65f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2388,7 +2388,11 @@ static inline struct file *file_clone_open(struct file *file) { return dentry_open(&file->f_path, file->f_flags, file->f_cred); } -extern int filp_close(struct file *, fl_owner_t id); +extern int __filp_close(struct file *file, fl_owner_t id, bool dofput); +static inline int filp_close(struct file *file, fl_owner_t id) +{ + return __filp_close(file, id, true); +} extern struct filename *getname_flags(const char __user *, int, int *);