summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@parcelfarce.linux.theplanet.co.uk>2003-05-20 06:58:17 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-05-20 06:58:17 -0700
commit32ccd2b61dfd05401528b27770ab3cd22b143641 (patch)
tree01cd62e23876962215deb49c4ff7105a65bdddfd
parentecdb306381de9308a484c29b28c03e2686aa00ae (diff)
[PATCH] seq_path(), /proc/mounts and /proc/swaps
This adds a new seq_...() helper: seq_path(seq_file, mnt, dentry, escape) It spits the pathname into seq_file, does octal escapes for given set of characters, returns the number of characters it'd produced or -1 in case of error. Long names are handled gracefully - you don't need anything to do, generic seq_file logics will do the right thing. /proc/mounts and /proc/swaps are converted to use of seq_path(), some junk removed. /proc/pid/maps will be converted next.
-rw-r--r--fs/dcache.c19
-rw-r--r--fs/namespace.c11
-rw-r--r--fs/seq_file.c31
-rw-r--r--include/linux/seq_file.h4
-rw-r--r--mm/swapfile.c16
5 files changed, 52 insertions, 29 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 33e861853287..4bbd819d97cf 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1275,7 +1275,7 @@ void d_move(struct dentry * dentry, struct dentry * target)
* the string " (deleted)" is appended. Note that this is ambiguous. Returns
* the buffer.
*
- * "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock.
+ * "buflen" should be positive. Caller holds the dcache_lock.
*/
static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt,
@@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
buflen -= 10;
end -= 10;
+ if (buflen < 0)
+ goto Elong;
memcpy(end, " (deleted)", 10);
}
+ if (buflen < 1)
+ goto Elong;
/* Get '/' right */
retval = end-1;
*retval = '/';
@@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
namelen = dentry->d_name.len;
buflen -= namelen + 1;
if (buflen < 0)
- return ERR_PTR(-ENAMETOOLONG);
+ goto Elong;
end -= namelen;
memcpy(end, dentry->d_name.name, namelen);
*--end = '/';
@@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
global_root:
namelen = dentry->d_name.len;
buflen -= namelen;
- if (buflen >= 0) {
- retval -= namelen-1; /* hit the slash */
- memcpy(retval, dentry->d_name.name, namelen);
- } else
- retval = ERR_PTR(-ENAMETOOLONG);
+ if (buflen < 0)
+ goto Elong;
+ retval -= namelen-1; /* hit the slash */
+ memcpy(retval, dentry->d_name.name, namelen);
return retval;
+Elong:
+ return ERR_PTR(-ENAMETOOLONG);
}
/* write full pathname into buffer and return start of pathname */
diff --git a/fs/namespace.c b/fs/namespace.c
index 6c46fbda724d..09238867b43b 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v)
{ 0, NULL }
};
struct proc_fs_info *fs_infop;
- char *path_buf, *path;
-
- path_buf = (char *) __get_free_page(GFP_KERNEL);
- if (!path_buf)
- return -ENOMEM;
- path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE);
- if (IS_ERR(path))
- path = " (too long)";
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
seq_putc(m, ' ');
- mangle(m, path);
- free_page((unsigned long) path_buf);
+ seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name);
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 98d7a01c14a4..7a9bcab37d49 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...)
return -1;
}
+int seq_path(struct seq_file *m,
+ struct vfsmount *mnt, struct dentry *dentry,
+ char *esc)
+{
+ if (m->count < m->size) {
+ char *s = m->buf + m->count;
+ char *p = d_path(dentry, mnt, s, m->size - m->count);
+ if (!IS_ERR(p)) {
+ while (s <= p) {
+ char c = *p++;
+ if (!c) {
+ p = m->buf + m->count;
+ m->count = s - m->buf;
+ return s - p;
+ } else if (!strchr(esc, c)) {
+ *s++ = c;
+ } else if (s + 4 > p) {
+ break;
+ } else {
+ *s++ = '\\';
+ *s++ = '0' + ((c & 0300) >> 6);
+ *s++ = '0' + ((c & 070) >> 3);
+ *s++ = '0' + (c & 07);
+ }
+ }
+ }
+ }
+ m->count = m->size;
+ return -1;
+}
+
static void *single_start(struct seq_file *p, loff_t *pos)
{
return NULL + (*pos == 0);
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index a704ab14e499..13df4750a271 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -8,6 +8,8 @@
struct seq_operations;
struct file;
+struct vfsmount;
+struct dentry;
struct inode;
struct seq_file {
@@ -58,6 +60,8 @@ static inline int seq_puts(struct seq_file *m, const char *s)
int seq_printf(struct seq_file *, const char *, ...)
__attribute__ ((format (printf,2,3)));
+int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);
+
int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct file *);
int seq_release_private(struct inode *, struct file *);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 55b2de7bca97..bdfd09be8d4c 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1118,14 +1118,9 @@ static void *swap_start(struct seq_file *swap, loff_t *pos)
struct swap_info_struct *ptr = swap_info;
int i;
loff_t l = *pos;
- char * page = (char *) __get_free_page(GFP_KERNEL);
- swap->private = page; /* save for swap_show */
swap_list_lock();
- if (!page)
- return ERR_PTR(-ENOMEM);
-
for (i = 0; i < nr_swapfiles; i++, ptr++) {
if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
continue;
@@ -1154,24 +1149,21 @@ static void *swap_next(struct seq_file *swap, void *v, loff_t *pos)
static void swap_stop(struct seq_file *swap, void *v)
{
swap_list_unlock();
- free_page((unsigned long) swap->private);
- swap->private = NULL;
}
static int swap_show(struct seq_file *swap, void *v)
{
struct swap_info_struct *ptr = v;
struct file *file;
- char *path;
+ int len;
if (v == swap_info)
seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
file = ptr->swap_file;
- path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE);
-
- seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n",
- path,
+ len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+ seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
+ len < 40 ? 40 - len : 1, " ",
S_ISBLK(file->f_dentry->d_inode->i_mode) ?
"partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10),