[PATCH] locks: new procfs lockinfo

From: Davidlohr Bueso
Date: Mon Feb 20 2012 - 06:31:00 EST


From: Davidlohr Bueso <dave@xxxxxxx>

Based on our previous discussion https://lkml.org/lkml/2012/2/10/462 we came to
agree on deprecating the current /proc/locks in favor of a more extensible interface.
The new /proc/lockinfo file exports similar information - except instead of maj:min the
device name is shown - and entries are formated like those in /proc/cpuinfo, allowing us
to add new entries without breaking userspace.

Signed-off-by: Davidlohr Bueso <dave@xxxxxxx>
---
Documentation/feature-removal-schedule.txt | 9 +++
fs/locks.c | 109 ++++++++++++++++++++++++++--
2 files changed, 113 insertions(+), 5 deletions(-)

diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index a0ffac0..1c5e14b 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -524,3 +524,12 @@ Files: arch/arm/mach-at91/at91cap9.c
Why: The code is not actively maintained and platforms are now hard to find.
Who: Nicolas Ferre <nicolas.ferre@xxxxxxxxx>
Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx>
+
+---------------------------
+
+What: /proc/locks
+When: 2014
+Why: The current /proc/locks file does not allow modifying entries as it breaks
+ userspace (most notably lslk(8)). A new /proc/lockinfo interface replaces
+ this file in a more extendable format (lines per entry), like /proc/cpuinfo.
+Who: Davidlohr Bueso <dave@xxxxxxx>
diff --git a/fs/locks.c b/fs/locks.c
index 637694b..f7b27fe 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -112,6 +112,9 @@
* Leases and LOCK_MAND
* Matthew Wilcox <willy@xxxxxxxxxx>, June, 2000.
* Stephen Rothwell <sfr@xxxxxxxxxxxxxxxx>, June, 2000.
+ *
+ * Deprecated /proc/locks in favor of /proc/lockinfo
+ * Davidlohr Bueso <dave@xxxxxxx>, February, 2012.
*/

#include <linux/capability.h>
@@ -2156,6 +2159,10 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
struct inode *inode = NULL;
unsigned int fl_pid;

+ /* deprecated, see Documentation/feature-removal-schedule.txt */
+ printk_once(KERN_WARNING "%s (%d): /proc/locks is deprecated please use /proc/lockinfo instead.\n",
+ current->comm, task_pid_nr(current));
+
if (fl->fl_nspid)
fl_pid = pid_vnr(fl->fl_nspid);
else
@@ -2199,15 +2206,10 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
}
if (inode) {
-#ifdef WE_CAN_BREAK_LSLK_NOW
- seq_printf(f, "%d %s:%ld ", fl_pid,
- inode->i_sb->s_id, inode->i_ino);
-#else
/* userspace relies on this representation of dev_t ;-( */
seq_printf(f, "%d %02x:%02x:%ld ", fl_pid,
MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev), inode->i_ino);
-#endif
} else {
seq_printf(f, "%d <none>:0 ", fl_pid);
}
@@ -2275,9 +2277,106 @@ static const struct file_operations proc_locks_operations = {
.release = seq_release_private,
};

+static void lockinfo_get_status(struct seq_file *f, struct file_lock *fl,
+ loff_t id)
+{
+ struct inode *inode = NULL;
+ unsigned int fl_pid;
+
+ if (fl->fl_nspid)
+ fl_pid = pid_vnr(fl->fl_nspid);
+ else
+ fl_pid = fl->fl_pid;
+
+ if (fl->fl_file != NULL)
+ inode = fl->fl_file->f_path.dentry->d_inode;
+
+ if (IS_POSIX(fl)) {
+ seq_printf(f, "Personality:\t %s\n",
+ (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ");
+ seq_printf(f, "Type:\t\t %s\n",
+ (!inode) ? "*NOINODE*" : mandatory_lock(inode)
+ ? "MANDATORY" : "ADVISORY ");
+ } else if (IS_FLOCK(fl)) {
+ seq_printf(f, "Personality:\t FLOCK\n");
+ seq_printf(f, "Type:\t\t %s\n",
+ (fl->fl_type & LOCK_MAND) ? "MSNFS" : "ADVISORY");
+ } else if (IS_LEASE(fl)) {
+ seq_printf(f, "Personality:\t LEASE\n");
+ seq_printf(f, "Type:\t\t %s\n",
+ (lease_breaking(fl)) ? "BREAKING"
+ : (fl->fl_file) ? "ACTIVE" : "BREAKER");
+ } else {
+ seq_printf(f, "Personality:\t UNKNOWN\n");
+ seq_printf(f, "Type:\t\t UNKNOWN\n");
+ }
+
+ if (fl->fl_type & LOCK_MAND) {
+ seq_printf(f, "Access:\t\t %s\n",
+ (fl->fl_type & LOCK_READ)
+ ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
+ : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
+ } else {
+ seq_printf(f, "Access:\t\t %s\n",
+ (lease_breaking(fl))
+ ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
+ : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
+ }
+
+ seq_printf(f, "PID:\t\t %d\n", fl_pid);
+
+ if (inode) {
+ seq_printf(f, "Device:\t\t %s\n", inode->i_sb->s_id);
+ seq_printf(f, "Inode:\t\t %ld\n", inode->i_ino);
+ }
+
+ if (IS_POSIX(fl)) {
+ if (fl->fl_end == OFFSET_MAX)
+ seq_printf(f, "Start-end:\t %Ld-EOF\n\n", fl->fl_start);
+ else
+ seq_printf(f, "Start-end:\t %Ld-%Ld\n\n", fl->fl_start, fl->fl_end);
+ } else {
+ seq_printf(f, "Start-end:\t 0-EOF\n\n");
+ }
+}
+
+static int lockinfo_show(struct seq_file *f, void *v)
+{
+ struct file_lock *fl, *bfl;
+
+ fl = list_entry(v, struct file_lock, fl_link);
+
+ lockinfo_get_status(f, fl, *((loff_t *)f->private));
+
+ list_for_each_entry(bfl, &fl->fl_block, fl_block)
+ lockinfo_get_status(f, bfl, *((loff_t *)f->private));
+
+ return 0;
+}
+
+static const struct seq_operations lockinfo_seq_operations = {
+ .start = locks_start,
+ .next = locks_next,
+ .stop = locks_stop,
+ .show = lockinfo_show,
+};
+
+static int lockinfo_open(struct inode *inode, struct file *filp)
+{
+ return seq_open_private(filp, &lockinfo_seq_operations, sizeof(loff_t));
+}
+
+static const struct file_operations proc_lockinfo_operations = {
+ .open = lockinfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static int __init proc_locks_init(void)
{
proc_create("locks", 0, NULL, &proc_locks_operations);
+ proc_create("lockinfo", 0, NULL, &proc_lockinfo_operations);
return 0;
}
module_init(proc_locks_init);
--
1.7.4.1



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/