Commit 97a54868 authored by Ben Hutchings's avatar Ben Hutchings Committed by Trond Myklebust

nfs: Show original device name verbatim in /proc/*/mount{s,info}

Since commit c7f404b4 ('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: default avatarChris Hiestand <chiestand@salk.edu>
Reference: http://bugs.debian.org/669314Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Cc: <stable@vger.kernel.org> # v2.6.39+
Signed-off-by: default avatarJonathan Nieder <jrnieder@gmail.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent acce94e6
...@@ -353,8 +353,9 @@ extern void nfs_sb_active(struct super_block *sb); ...@@ -353,8 +353,9 @@ extern void nfs_sb_active(struct super_block *sb);
extern void nfs_sb_deactive(struct super_block *sb); extern void nfs_sb_deactive(struct super_block *sb);
/* namespace.c */ /* namespace.c */
#define NFS_PATH_CANONICAL 1
extern char *nfs_path(char **p, struct dentry *dentry, 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); extern struct vfsmount *nfs_d_automount(struct path *path);
struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *, struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
struct nfs_fh *, struct nfs_fattr *); struct nfs_fh *, struct nfs_fattr *);
...@@ -498,7 +499,7 @@ static inline char *nfs_devname(struct dentry *dentry, ...@@ -498,7 +499,7 @@ static inline char *nfs_devname(struct dentry *dentry,
char *buffer, ssize_t buflen) char *buffer, ssize_t buflen)
{ {
char *dummy; char *dummy;
return nfs_path(&dummy, dentry, buffer, buflen); return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL);
} }
/* /*
......
...@@ -33,6 +33,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; ...@@ -33,6 +33,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
* @dentry - pointer to dentry * @dentry - pointer to dentry
* @buffer - result buffer * @buffer - result buffer
* @buflen - length of buffer * @buflen - length of buffer
* @flags - options (see below)
* *
* Helper function for constructing the server pathname * Helper function for constructing the server pathname
* by arbitrary hashed dentry. * by arbitrary hashed dentry.
...@@ -40,8 +41,14 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; ...@@ -40,8 +41,14 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
* This is mainly for use in figuring out the path on the * This is mainly for use in figuring out the path on the
* server side when automounting on top of an existing partition * server side when automounting on top of an existing partition
* and in generating /proc/mounts and friends. * 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; char *end;
int namelen; int namelen;
...@@ -74,7 +81,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) ...@@ -74,7 +81,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
rcu_read_unlock(); rcu_read_unlock();
goto rename_retry; goto rename_retry;
} }
if (*end != '/') { if ((flags & NFS_PATH_CANONICAL) && *end != '/') {
if (--buflen < 0) { if (--buflen < 0) {
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
rcu_read_unlock(); rcu_read_unlock();
...@@ -91,9 +98,11 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) ...@@ -91,9 +98,11 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
return end; return end;
} }
namelen = strlen(base); namelen = strlen(base);
if (flags & NFS_PATH_CANONICAL) {
/* Strip off excess slashes in base string */ /* Strip off excess slashes in base string */
while (namelen > 0 && base[namelen - 1] == '/') while (namelen > 0 && base[namelen - 1] == '/')
namelen--; namelen--;
}
buflen -= namelen; buflen -= namelen;
if (buflen < 0) { if (buflen < 0) {
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
......
...@@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end) ...@@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end)
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
{ {
char *limit; 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)) { if (!IS_ERR(path)) {
char *path_component = nfs_path_component(path, limit); char *path_component = nfs_path_component(path, limit);
if (path_component) if (path_component)
......
...@@ -771,7 +771,7 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root) ...@@ -771,7 +771,7 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root)
int err = 0; int err = 0;
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
devname = nfs_path(&dummy, root, page, PAGE_SIZE); devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0);
if (IS_ERR(devname)) if (IS_ERR(devname))
err = PTR_ERR(devname); err = PTR_ERR(devname);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment