summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/internal.h1
-rw-r--r--fs/open.c17
2 files changed, 15 insertions, 3 deletions
diff --git a/fs/internal.h b/fs/internal.h
index c658c8a5ebd5..8812de210d3f 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -198,6 +198,7 @@ extern struct file *do_file_open_root(const struct path *,
extern struct open_how build_open_how(int flags, umode_t mode);
extern int build_open_flags(const struct open_how *how, struct open_flags *op);
struct file *file_close_fd_locked(struct files_struct *files, unsigned fd);
+int filp_close_sync(struct file *filp, fl_owner_t id);
int do_ftruncate(struct file *file, loff_t length, unsigned int flags);
int chmod_common(const struct path *path, umode_t mode);
diff --git a/fs/open.c b/fs/open.c
index 6b1c14e684a9..998e42ac319a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1537,6 +1537,19 @@ int filp_close(struct file *filp, fl_owner_t id)
}
EXPORT_SYMBOL(filp_close);
+/* Like filp_close() but the last reference is put right here. */
+int filp_close_sync(struct file *filp, fl_owner_t id)
+{
+ int retval;
+
+ /* Kernel threads must never put their final reference here. */
+ VFS_WARN_ON_ONCE(current->flags & PF_KTHREAD);
+ retval = filp_flush(filp, id);
+ fput_close_sync(filp);
+
+ return retval;
+}
+
/*
* Careful here! We test whether the file pointer is NULL before
* releasing the fd. This ensures that one clone task can't release
@@ -1551,13 +1564,11 @@ SYSCALL_DEFINE1(close, unsigned int, fd)
if (!file)
return -EBADF;
- retval = filp_flush(file, current->files);
-
/*
* We're returning to user space. Don't bother
* with any delayed fput() cases.
*/
- fput_close_sync(file);
+ retval = filp_close_sync(file, current->files);
if (likely(retval == 0))
return 0;