| From 97a54868262da1629a3e65121e65b8e8c4419d9f Mon Sep 17 00:00:00 2001 |
| From: Ben Hutchings <ben@decadent.org.uk> |
| Date: Sun, 21 Oct 2012 19:23:52 +0100 |
| Subject: nfs: Show original device name verbatim in /proc/*/mount{s,info} |
| |
| From: Ben Hutchings <ben@decadent.org.uk> |
| |
| commit 97a54868262da1629a3e65121e65b8e8c4419d9f upstream. |
| |
| Since commit c7f404b ('vfs: new superblock methods to override |
| /proc/*/mount{s,info}'), nfs_path() is used to generate the mounted |
| device name reported back to userland. |
| |
| nfs_path() always generates a trailing slash when the given dentry is |
| the root of an NFS mount, but userland may expect the original device |
| name to be returned verbatim (as it used to be). Make this |
| canonicalisation optional and change the callers accordingly. |
| |
| [jrnieder@gmail.com: use flag instead of bool argument] |
| Reported-and-tested-by: Chris Hiestand <chiestand@salk.edu> |
| Reference: http://bugs.debian.org/669314 |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> |
| Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/nfs/internal.h | 5 +++-- |
| fs/nfs/namespace.c | 19 ++++++++++++++----- |
| fs/nfs/nfs4namespace.c | 3 ++- |
| fs/nfs/super.c | 2 +- |
| 4 files changed, 20 insertions(+), 9 deletions(-) |
| |
| --- a/fs/nfs/internal.h |
| +++ b/fs/nfs/internal.h |
| @@ -274,8 +274,9 @@ extern void nfs_sb_active(struct super_b |
| extern void nfs_sb_deactive(struct super_block *sb); |
| |
| /* namespace.c */ |
| +#define NFS_PATH_CANONICAL 1 |
| extern char *nfs_path(char **p, struct dentry *dentry, |
| - char *buffer, ssize_t buflen); |
| + char *buffer, ssize_t buflen, unsigned flags); |
| extern struct vfsmount *nfs_d_automount(struct path *path); |
| |
| /* getroot.c */ |
| @@ -349,7 +350,7 @@ static inline char *nfs_devname(struct d |
| char *buffer, ssize_t buflen) |
| { |
| char *dummy; |
| - return nfs_path(&dummy, dentry, buffer, buflen); |
| + return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL); |
| } |
| |
| /* |
| --- a/fs/nfs/namespace.c |
| +++ b/fs/nfs/namespace.c |
| @@ -37,6 +37,7 @@ static struct vfsmount *nfs_do_submount( |
| * @dentry - pointer to dentry |
| * @buffer - result buffer |
| * @buflen - length of buffer |
| + * @flags - options (see below) |
| * |
| * Helper function for constructing the server pathname |
| * by arbitrary hashed dentry. |
| @@ -44,8 +45,14 @@ static struct vfsmount *nfs_do_submount( |
| * This is mainly for use in figuring out the path on the |
| * server side when automounting on top of an existing partition |
| * and in generating /proc/mounts and friends. |
| + * |
| + * Supported flags: |
| + * NFS_PATH_CANONICAL: ensure there is exactly one slash after |
| + * the original device (export) name |
| + * (if unset, the original name is returned verbatim) |
| */ |
| -char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) |
| +char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen, |
| + unsigned flags) |
| { |
| char *end; |
| int namelen; |
| @@ -78,7 +85,7 @@ rename_retry: |
| rcu_read_unlock(); |
| goto rename_retry; |
| } |
| - if (*end != '/') { |
| + if ((flags & NFS_PATH_CANONICAL) && *end != '/') { |
| if (--buflen < 0) { |
| spin_unlock(&dentry->d_lock); |
| rcu_read_unlock(); |
| @@ -95,9 +102,11 @@ rename_retry: |
| return end; |
| } |
| namelen = strlen(base); |
| - /* Strip off excess slashes in base string */ |
| - while (namelen > 0 && base[namelen - 1] == '/') |
| - namelen--; |
| + if (flags & NFS_PATH_CANONICAL) { |
| + /* Strip off excess slashes in base string */ |
| + while (namelen > 0 && base[namelen - 1] == '/') |
| + namelen--; |
| + } |
| buflen -= namelen; |
| if (buflen < 0) { |
| spin_unlock(&dentry->d_lock); |
| --- a/fs/nfs/nfs4namespace.c |
| +++ b/fs/nfs/nfs4namespace.c |
| @@ -57,7 +57,8 @@ Elong: |
| static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
| { |
| char *limit; |
| - char *path = nfs_path(&limit, dentry, buffer, buflen); |
| + char *path = nfs_path(&limit, dentry, buffer, buflen, |
| + NFS_PATH_CANONICAL); |
| if (!IS_ERR(path)) { |
| char *colon = strchr(path, ':'); |
| if (colon && colon < limit) |
| --- a/fs/nfs/super.c |
| +++ b/fs/nfs/super.c |
| @@ -763,7 +763,7 @@ static int nfs_show_devname(struct seq_f |
| int err = 0; |
| if (!page) |
| return -ENOMEM; |
| - devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE); |
| + devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE, 0); |
| if (IS_ERR(devname)) |
| err = PTR_ERR(devname); |
| else |