Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'locks-v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux

Pull file locking updates from Jeff Layton:
"Just a couple of small lease-related patches this cycle.

One from Ira to add a new tracepoint that fires during lease conflict
checks, and another patch from Amir to reduce false positives when
checking for lease conflicts"

* tag 'locks-v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux:
locks: eliminate false positive conflicts for write lease
locks: Add trace_leases_conflict

+79 -22
+42 -20
fs/locks.c
··· 1534 1534 1535 1535 static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) 1536 1536 { 1537 - if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) 1538 - return false; 1539 - if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) 1540 - return false; 1541 - return locks_conflict(breaker, lease); 1537 + bool rc; 1538 + 1539 + if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) { 1540 + rc = false; 1541 + goto trace; 1542 + } 1543 + if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) { 1544 + rc = false; 1545 + goto trace; 1546 + } 1547 + 1548 + rc = locks_conflict(breaker, lease); 1549 + trace: 1550 + trace_leases_conflict(rc, lease, breaker); 1551 + return rc; 1542 1552 } 1543 1553 1544 1554 static bool ··· 1763 1753 } 1764 1754 1765 1755 /** 1766 - * check_conflicting_open - see if the given dentry points to a file that has 1756 + * check_conflicting_open - see if the given file points to an inode that has 1767 1757 * an existing open that would conflict with the 1768 1758 * desired lease. 1769 - * @dentry: dentry to check 1759 + * @filp: file to check 1770 1760 * @arg: type of lease that we're trying to acquire 1771 1761 * @flags: current lock flags 1772 1762 * ··· 1774 1764 * conflict with the lease we're trying to set. 1775 1765 */ 1776 1766 static int 1777 - check_conflicting_open(const struct dentry *dentry, const long arg, int flags) 1767 + check_conflicting_open(struct file *filp, const long arg, int flags) 1778 1768 { 1779 - int ret = 0; 1780 - struct inode *inode = dentry->d_inode; 1769 + struct inode *inode = locks_inode(filp); 1770 + int self_wcount = 0, self_rcount = 0; 1781 1771 1782 1772 if (flags & FL_LAYOUT) 1783 1773 return 0; 1784 1774 1785 - if ((arg == F_RDLCK) && inode_is_open_for_write(inode)) 1775 + if (arg == F_RDLCK) 1776 + return inode_is_open_for_write(inode) ? -EAGAIN : 0; 1777 + else if (arg != F_WRLCK) 1778 + return 0; 1779 + 1780 + /* 1781 + * Make sure that only read/write count is from lease requestor. 1782 + * Note that this will result in denying write leases when i_writecount 1783 + * is negative, which is what we want. (We shouldn't grant write leases 1784 + * on files open for execution.) 1785 + */ 1786 + if (filp->f_mode & FMODE_WRITE) 1787 + self_wcount = 1; 1788 + else if (filp->f_mode & FMODE_READ) 1789 + self_rcount = 1; 1790 + 1791 + if (atomic_read(&inode->i_writecount) != self_wcount || 1792 + atomic_read(&inode->i_readcount) != self_rcount) 1786 1793 return -EAGAIN; 1787 1794 1788 - if ((arg == F_WRLCK) && ((d_count(dentry) > 1) || 1789 - (atomic_read(&inode->i_count) > 1))) 1790 - ret = -EAGAIN; 1791 - 1792 - return ret; 1795 + return 0; 1793 1796 } 1794 1797 1795 1798 static int 1796 1799 generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv) 1797 1800 { 1798 1801 struct file_lock *fl, *my_fl = NULL, *lease; 1799 - struct dentry *dentry = filp->f_path.dentry; 1800 - struct inode *inode = dentry->d_inode; 1802 + struct inode *inode = locks_inode(filp); 1801 1803 struct file_lock_context *ctx; 1802 1804 bool is_deleg = (*flp)->fl_flags & FL_DELEG; 1803 1805 int error; ··· 1844 1822 percpu_down_read(&file_rwsem); 1845 1823 spin_lock(&ctx->flc_lock); 1846 1824 time_out_leases(inode, &dispose); 1847 - error = check_conflicting_open(dentry, arg, lease->fl_flags); 1825 + error = check_conflicting_open(filp, arg, lease->fl_flags); 1848 1826 if (error) 1849 1827 goto out; 1850 1828 ··· 1901 1879 * precedes these checks. 1902 1880 */ 1903 1881 smp_mb(); 1904 - error = check_conflicting_open(dentry, arg, lease->fl_flags); 1882 + error = check_conflicting_open(filp, arg, lease->fl_flags); 1905 1883 if (error) { 1906 1884 locks_unlink_lock_ctx(lease); 1907 1885 goto out;
+2 -2
include/linux/fs.h
··· 694 694 atomic_t i_count; 695 695 atomic_t i_dio_count; 696 696 atomic_t i_writecount; 697 - #ifdef CONFIG_IMA 697 + #if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING) 698 698 atomic_t i_readcount; /* struct files open RO */ 699 699 #endif 700 700 union { ··· 2890 2890 return atomic_read(&inode->i_writecount) > 0; 2891 2891 } 2892 2892 2893 - #ifdef CONFIG_IMA 2893 + #if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING) 2894 2894 static inline void i_readcount_dec(struct inode *inode) 2895 2895 { 2896 2896 BUG_ON(!atomic_read(&inode->i_readcount));
+35
include/trace/events/filelock.h
··· 203 203 show_fl_type(__entry->fl_type)) 204 204 ); 205 205 206 + TRACE_EVENT(leases_conflict, 207 + TP_PROTO(bool conflict, struct file_lock *lease, struct file_lock *breaker), 208 + 209 + TP_ARGS(conflict, lease, breaker), 210 + 211 + TP_STRUCT__entry( 212 + __field(void *, lease) 213 + __field(void *, breaker) 214 + __field(unsigned int, l_fl_flags) 215 + __field(unsigned int, b_fl_flags) 216 + __field(unsigned char, l_fl_type) 217 + __field(unsigned char, b_fl_type) 218 + __field(bool, conflict) 219 + ), 220 + 221 + TP_fast_assign( 222 + __entry->lease = lease; 223 + __entry->l_fl_flags = lease->fl_flags; 224 + __entry->l_fl_type = lease->fl_type; 225 + __entry->breaker = breaker; 226 + __entry->b_fl_flags = breaker->fl_flags; 227 + __entry->b_fl_type = breaker->fl_type; 228 + __entry->conflict = conflict; 229 + ), 230 + 231 + TP_printk("conflict %d: lease=0x%p fl_flags=%s fl_type=%s; breaker=0x%p fl_flags=%s fl_type=%s", 232 + __entry->conflict, 233 + __entry->lease, 234 + show_fl_flags(__entry->l_fl_flags), 235 + show_fl_type(__entry->l_fl_type), 236 + __entry->breaker, 237 + show_fl_flags(__entry->b_fl_flags), 238 + show_fl_type(__entry->b_fl_type)) 239 + ); 240 + 206 241 #endif /* _TRACE_FILELOCK_H */ 207 242 208 243 /* This part must be outside protection */