Skip to content

Commit

Permalink
Rework /proc/locks via seq_files and seq_list helpers
Browse files Browse the repository at this point in the history
Currently /proc/locks is shown with a proc_read function, but its behavior
is rather complex as it has to manually handle current offset and buffer
length.  On the other hand, files that show objects from lists can be
easily reimplemented using the sequential files and the seq_list_XXX()
helpers.

This saves (as usually) 16 lines of code and more than 200 from
the .text section.

[akpm@linux-foundation.org: no externs in C]
[akpm@linux-foundation.org: warning fixes]
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Cc: "J. Bruce Fields" <bfields@fieldses.org>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
  • Loading branch information
Pavel Emelyanov authored and J. Bruce Fields committed Oct 9, 2007
1 parent 094f282 commit 7f8ada9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 80 deletions.
122 changes: 51 additions & 71 deletions fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -2066,134 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl)

EXPORT_SYMBOL_GPL(vfs_cancel_lock);

static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
#ifdef CONFIG_PROC_FS
#include <linux/seq_file.h>

static void lock_get_status(struct seq_file *f, struct file_lock *fl,
int id, char *pfx)
{
struct inode *inode = NULL;

if (fl->fl_file != NULL)
inode = fl->fl_file->f_path.dentry->d_inode;

out += sprintf(out, "%d:%s ", id, pfx);
seq_printf(f, "%d:%s ", id, pfx);
if (IS_POSIX(fl)) {
out += sprintf(out, "%6s %s ",
seq_printf(f, "%6s %s ",
(fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
(inode == NULL) ? "*NOINODE*" :
mandatory_lock(inode) ? "MANDATORY" : "ADVISORY ");
} else if (IS_FLOCK(fl)) {
if (fl->fl_type & LOCK_MAND) {
out += sprintf(out, "FLOCK MSNFS ");
seq_printf(f, "FLOCK MSNFS ");
} else {
out += sprintf(out, "FLOCK ADVISORY ");
seq_printf(f, "FLOCK ADVISORY ");
}
} else if (IS_LEASE(fl)) {
out += sprintf(out, "LEASE ");
seq_printf(f, "LEASE ");
if (fl->fl_type & F_INPROGRESS)
out += sprintf(out, "BREAKING ");
seq_printf(f, "BREAKING ");
else if (fl->fl_file)
out += sprintf(out, "ACTIVE ");
seq_printf(f, "ACTIVE ");
else
out += sprintf(out, "BREAKER ");
seq_printf(f, "BREAKER ");
} else {
out += sprintf(out, "UNKNOWN UNKNOWN ");
seq_printf(f, "UNKNOWN UNKNOWN ");
}
if (fl->fl_type & LOCK_MAND) {
out += sprintf(out, "%s ",
seq_printf(f, "%s ",
(fl->fl_type & LOCK_READ)
? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
: (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
} else {
out += sprintf(out, "%s ",
seq_printf(f, "%s ",
(fl->fl_type & F_INPROGRESS)
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
}
if (inode) {
#ifdef WE_CAN_BREAK_LSLK_NOW
out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
seq_printf(f, "%d %s:%ld ", fl->fl_pid,
inode->i_sb->s_id, inode->i_ino);
#else
/* userspace relies on this representation of dev_t ;-( */
out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid,
seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid,
MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev), inode->i_ino);
#endif
} else {
out += sprintf(out, "%d <none>:0 ", fl->fl_pid);
seq_printf(f, "%d <none>:0 ", fl->fl_pid);
}
if (IS_POSIX(fl)) {
if (fl->fl_end == OFFSET_MAX)
out += sprintf(out, "%Ld EOF\n", fl->fl_start);
seq_printf(f, "%Ld EOF\n", fl->fl_start);
else
out += sprintf(out, "%Ld %Ld\n", fl->fl_start,
fl->fl_end);
seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end);
} else {
out += sprintf(out, "0 EOF\n");
seq_printf(f, "0 EOF\n");
}
}

static void move_lock_status(char **p, off_t* pos, off_t offset)
static int locks_show(struct seq_file *f, void *v)
{
int len;
len = strlen(*p);
if(*pos >= offset) {
/* the complete line is valid */
*p += len;
*pos += len;
return;
}
if(*pos+len > offset) {
/* use the second part of the line */
int i = offset-*pos;
memmove(*p,*p+i,len-i);
*p += len-i;
*pos += len;
return;
}
/* discard the complete line */
*pos += len;
}
struct file_lock *fl, *bfl;

/**
* get_locks_status - reports lock usage in /proc/locks
* @buffer: address in userspace to write into
* @start: ?
* @offset: how far we are through the buffer
* @length: how much to read
*/
fl = list_entry(v, struct file_lock, fl_link);

int get_locks_status(char *buffer, char **start, off_t offset, int length)
{
struct file_lock *fl;
char *q = buffer;
off_t pos = 0;
int i = 0;
lock_get_status(f, fl, (long)f->private, "");

lock_kernel();
list_for_each_entry(fl, &file_lock_list, fl_link) {
struct file_lock *bfl;
list_for_each_entry(bfl, &fl->fl_block, fl_block)
lock_get_status(f, bfl, (long)f->private, " ->");

lock_get_status(q, fl, ++i, "");
move_lock_status(&q, &pos, offset);
f->private++;
return 0;
}

if(pos >= offset+length)
goto done;
static void *locks_start(struct seq_file *f, loff_t *pos)
{
lock_kernel();
f->private = (void *)1;
return seq_list_start(&file_lock_list, *pos);
}

list_for_each_entry(bfl, &fl->fl_block, fl_block) {
lock_get_status(q, bfl, i, " ->");
move_lock_status(&q, &pos, offset);
static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
{
return seq_list_next(v, &file_lock_list, pos);
}

if(pos >= offset+length)
goto done;
}
}
done:
static void locks_stop(struct seq_file *f, void *v)
{
unlock_kernel();
*start = buffer;
if(q-buffer < length)
return (q-buffer);
return length;
}

struct seq_operations locks_seq_operations = {
.start = locks_start,
.next = locks_next,
.stop = locks_stop,
.show = locks_show,
};
#endif

/**
* lock_may_read - checks that the region is free of locks
* @inode: the inode that is being read
Expand Down
19 changes: 10 additions & 9 deletions fs/proc/proc_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ extern int get_stram_list(char *);
extern int get_filesystem_list(char *);
extern int get_exec_domain_list(char *);
extern int get_dma_list(char *);
extern int get_locks_status (char *, char **, off_t, int);

static int proc_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
Expand Down Expand Up @@ -617,16 +616,18 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
return proc_calc_metrics(page, start, off, count, eof, len);
}

static int locks_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
static int locks_open(struct inode *inode, struct file *filp)
{
int len = get_locks_status(page, start, off, count);

if (len < count)
*eof = 1;
return len;
return seq_open(filp, &locks_seq_operations);
}

static const struct file_operations proc_locks_operations = {
.open = locks_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};

static int execdomains_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
Expand Down Expand Up @@ -684,7 +685,6 @@ void __init proc_misc_init(void)
#endif
{"filesystems", filesystems_read_proc},
{"cmdline", cmdline_read_proc},
{"locks", locks_read_proc},
{"execdomains", execdomains_read_proc},
{NULL,}
};
Expand All @@ -702,6 +702,7 @@ void __init proc_misc_init(void)
entry->proc_fops = &proc_kmsg_operations;
}
#endif
create_seq_entry("locks", 0, &proc_locks_operations);
create_seq_entry("devices", 0, &proc_devinfo_operations);
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
#ifdef CONFIG_BLOCK
Expand Down
1 change: 1 addition & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
extern struct seq_operations locks_seq_operations;

struct fasync_struct {
int magic;
Expand Down

0 comments on commit 7f8ada9

Please sign in to comment.