[RFC PATCH 08/10] mm/gup: fs: Send SIGBUS on truncate of active file

From: ira . weiny
Date: Mon Apr 29 2019 - 00:54:43 EST


From: Ira Weiny <ira.weiny@xxxxxxxxx>

Now that the taking of LONGTERM leases is in place we can now facilitate
sending a SIGBUS to process if a file truncate or hole punch is
performed and they do not respond by releasing the lease.

The standard file lease_break_time is used to time out the LONGTERM
lease which is in place on the inode.
---
fs/ext4/inode.c | 4 ++++
fs/locks.c | 13 +++++++++++--
fs/xfs/xfs_file.c | 4 ++++
include/linux/fs.h | 13 +++++++++++++
4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b32a57bc5d5d..bee456c8c805 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4237,6 +4237,10 @@ int ext4_break_layouts(struct inode *inode)
if (WARN_ON_ONCE(!rwsem_is_locked(&ei->i_mmap_sem)))
return -EINVAL;

+ /* Break longterm leases */
+ if (dax_mapping_is_dax(inode->i_mapping))
+ break_longterm(inode);
+
do {
page = dax_layout_busy_page(inode->i_mapping);
if (!page)
diff --git a/fs/locks.c b/fs/locks.c
index 58c6d7a411b6..c77eee081d11 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1580,6 +1580,7 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose)
{
struct file_lock_context *ctx = inode->i_flctx;
struct file_lock *fl, *tmp;
+ struct task_struct *tsk;

lockdep_assert_held(&ctx->flc_lock);

@@ -1587,8 +1588,16 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose)
trace_time_out_leases(inode, fl);
if (past_time(fl->fl_downgrade_time))
lease_modify(fl, F_RDLCK, dispose);
- if (past_time(fl->fl_break_time))
- lease_modify(fl, F_UNLCK, dispose);
+ if (past_time(fl->fl_break_time)) {
+ if (fl->fl_flags & FL_LONGTERM) {
+ tsk = find_task_by_vpid(fl->fl_pid);
+ fl->fl_break_time = 1 + jiffies + lease_break_time * HZ;
+ lease_modify_longterm(fl, F_UNLCK, dispose);
+ kill_pid(tsk->thread_pid, SIGBUS, 0);
+ } else {
+ lease_modify(fl, F_UNLCK, dispose);
+ }
+ }
}
}

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 1f2e2845eb76..ebd310f3ae65 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -739,6 +739,10 @@ xfs_break_dax_layouts(

ASSERT(xfs_isilocked(XFS_I(inode), XFS_MMAPLOCK_EXCL));

+ /* Break longterm leases */
+ if (dax_mapping_is_dax(inode->i_mapping))
+ break_longterm(inode);
+
page = dax_layout_busy_page(inode->i_mapping);
if (!page)
return 0;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index be2d08080aa5..0e8b21240a71 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2459,6 +2459,14 @@ static inline int break_layout(struct inode *inode, bool wait)
return 0;
}

+static inline int break_longterm(struct inode *inode)
+{
+ smp_mb();
+ if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease))
+ return __break_lease(inode, O_WRONLY, FL_LONGTERM);
+ return 0;
+}
+
#else /* !CONFIG_FILE_LOCKING */
static inline int break_lease(struct inode *inode, unsigned int mode)
{
@@ -2486,6 +2494,11 @@ static inline int break_layout(struct inode *inode, bool wait)
return 0;
}

+static inline int break_longterm(struct inode *inode, bool wait)
+{
+ return 0;
+}
+
#endif /* CONFIG_FILE_LOCKING */

/* fs/open.c */
--
2.20.1