Commit 726c3342 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

[PATCH] VFS: Permit filesystem to perform statfs with a known root dentry



Give the statfs superblock operation a dentry pointer rather than a superblock
pointer.

This complements the get_sb() patch.  That reduced the significance of
sb->s_root, allowing NFS to place a fake root there.  However, NFS does
require a dentry to use as a target for the statfs operation.  This permits
the root in the vfsmount to be used instead.

linux/mount.h has been added where necessary to make allyesconfig build
successfully.

Interest has also been expressed for use with the FUSE and XFS filesystems.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Cc: Nathan Scott <nathans@sgi.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 454e2398
......@@ -31,18 +31,18 @@
#include <asm/unistd.h>
int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int retval = -ENODEV;
if (sb) {
if (dentry) {
retval = -ENOSYS;
if (sb->s_op->statfs) {
if (dentry->d_sb->s_op->statfs) {
memset(buf, 0, sizeof(*buf));
retval = security_sb_statfs(sb);
retval = security_sb_statfs(dentry);
if (retval)
return retval;
retval = sb->s_op->statfs(sb, buf);
retval = dentry->d_sb->s_op->statfs(dentry, buf);
if (retval == 0 && buf->f_frsize == 0)
buf->f_frsize = buf->f_bsize;
}
......@@ -52,12 +52,12 @@ int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
EXPORT_SYMBOL(vfs_statfs);
static int vfs_statfs_native(struct super_block *sb, struct statfs *buf)
static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
{
struct kstatfs st;
int retval;
retval = vfs_statfs(sb, &st);
retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
......@@ -95,12 +95,12 @@ static int vfs_statfs_native(struct super_block *sb, struct statfs *buf)
return 0;
}
static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf)
static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
{
struct kstatfs st;
int retval;
retval = vfs_statfs(sb, &st);
retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
......@@ -130,7 +130,7 @@ asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf)
error = user_path_walk(path, &nd);
if (!error) {
struct statfs tmp;
error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp);
error = vfs_statfs_native(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
......@@ -149,7 +149,7 @@ asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64
error = user_path_walk(path, &nd);
if (!error) {
struct statfs64 tmp;
error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp);
error = vfs_statfs64(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
......@@ -168,7 +168,7 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf)
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp);
error = vfs_statfs_native(file->f_dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
......@@ -189,7 +189,7 @@ asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp);
error = vfs_statfs64(file->f_dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
......
......@@ -128,7 +128,7 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb);
static void qnx4_destroy_inode(struct inode *inode);
static void qnx4_read_inode(struct inode *);
static int qnx4_remount(struct super_block *sb, int *flags, char *data);
static int qnx4_statfs(struct super_block *, struct kstatfs *);
static int qnx4_statfs(struct dentry *, struct kstatfs *);
static struct super_operations qnx4_sops =
{
......@@ -282,8 +282,10 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
return block;
}
static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf)
static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
lock_kernel();
buf->f_type = sb->s_magic;
......
......@@ -60,7 +60,7 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
}
static int reiserfs_remount(struct super_block *s, int *flags, char *data);
static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf);
static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int reiserfs_sync_fs(struct super_block *s, int wait)
{
......@@ -1938,15 +1938,15 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
return errval;
}
static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf)
static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(dentry->d_sb);
buf->f_namelen = (REISERFS_MAX_NAME(s->s_blocksize));
buf->f_bfree = sb_free_blocks(rs);
buf->f_bavail = buf->f_bfree;
buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
buf->f_bsize = s->s_blocksize;
buf->f_bsize = dentry->d_sb->s_blocksize;
/* changed to accommodate gcc folks. */
buf->f_type = REISERFS_SUPER_MAGIC;
return 0;
......
......@@ -179,12 +179,12 @@ outnobh:
/* That's simple too. */
static int
romfs_statfs(struct super_block *sb, struct kstatfs *buf)
romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
buf->f_type = ROMFS_MAGIC;
buf->f_bsize = ROMBSIZE;
buf->f_bfree = buf->f_bavail = buf->f_ffree;
buf->f_blocks = (romfs_maxsize(sb)+ROMBSIZE-1)>>ROMBSBITS;
buf->f_blocks = (romfs_maxsize(dentry->d_sb)+ROMBSIZE-1)>>ROMBSBITS;
buf->f_namelen = ROMFS_MAXFN;
return 0;
}
......
......@@ -48,7 +48,7 @@
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
static int smb_statfs(struct super_block *, struct kstatfs *);
static int smb_statfs(struct dentry *, struct kstatfs *);
static int smb_show_options(struct seq_file *, struct vfsmount *);
static kmem_cache_t *smb_inode_cachep;
......@@ -641,13 +641,13 @@ out_no_server:
}
static int
smb_statfs(struct super_block *sb, struct kstatfs *buf)
smb_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int result;
lock_kernel();
result = smb_proc_dskattr(sb, buf);
result = smb_proc_dskattr(dentry, buf);
unlock_kernel();
......
......@@ -3226,9 +3226,9 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
}
int
smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr)
smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr)
{
struct smb_sb_info *server = SMB_SB(sb);
struct smb_sb_info *server = SMB_SB(dentry->d_sb);
int result;
char *p;
long unit;
......
......@@ -29,7 +29,7 @@ extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, unsigned int major, unsigned int minor);
extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
extern int smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr);
extern int smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr);
extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len);
extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath);
extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
......
......@@ -486,7 +486,7 @@ asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf)
s = user_get_super(new_decode_dev(dev));
if (s == NULL)
goto out;
err = vfs_statfs(s, &sbuf);
err = vfs_statfs(s->s_root, &sbuf);
drop_super(s);
if (err)
goto out;
......
......@@ -85,8 +85,9 @@ static void sysv_put_super(struct super_block *sb)
kfree(sbi);
}
static int sysv_statfs(struct super_block *sb, struct kstatfs *buf)
static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct sysv_sb_info *sbi = SYSV_SB(sb);
buf->f_type = sb->s_magic;
......
......@@ -91,7 +91,7 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *);
static void udf_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *);
static unsigned int udf_count_free(struct super_block *);
static int udf_statfs(struct super_block *, struct kstatfs *);
static int udf_statfs(struct dentry *, struct kstatfs *);
/* UDF filesystem type */
static int udf_get_sb(struct file_system_type *fs_type,
......@@ -1779,8 +1779,10 @@ udf_put_super(struct super_block *sb)
* Written, tested, and released.
*/
static int
udf_statfs(struct super_block *sb, struct kstatfs *buf)
udf_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
buf->f_type = UDF_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
......
......@@ -1113,8 +1113,9 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
return 0;
}
static int ufs_statfs (struct super_block *sb, struct kstatfs *buf)
static int ufs_statfs (struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
struct ufs_super_block * usb;
......
......@@ -684,10 +684,10 @@ xfs_fs_sync_super(
STATIC int
xfs_fs_statfs(
struct super_block *sb,
struct dentry *dentry,
struct kstatfs *statp)
{
return -bhv_vfs_statvfs(vfs_from_sb(sb), statp, NULL);
return -bhv_vfs_statvfs(vfs_from_sb(dentry->d_sb), statp, NULL);
}
STATIC int
......
......@@ -70,7 +70,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
unsigned int cmd, struct PioctlData *data);
int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
int venus_fsync(struct super_block *sb, struct CodaFid *fid);
int venus_statfs(struct super_block *sb, struct kstatfs *sfs);
int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
/* messages between coda filesystem in kernel and Venus */
......
......@@ -1096,7 +1096,7 @@ struct super_operations {
int (*sync_fs)(struct super_block *sb, int wait);
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);
int (*statfs) (struct super_block *, struct kstatfs *);
int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
......@@ -1325,7 +1325,7 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
struct vfsmount *);
extern int vfs_statfs(struct super_block *, struct kstatfs *);
extern int vfs_statfs(struct dentry *, struct kstatfs *);
/* /sys/fs */
extern struct subsystem fs_subsys;
......@@ -1746,7 +1746,7 @@ extern int dcache_dir_close(struct inode *, struct file *);
extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
extern int dcache_readdir(struct file *, void *, filldir_t);
extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int simple_statfs(struct super_block *, struct kstatfs *);
extern int simple_statfs(struct dentry *, struct kstatfs *);
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
extern int simple_unlink(struct inode *, struct dentry *);
extern int simple_rmdir(struct inode *, struct dentry *);
......
......@@ -17,6 +17,11 @@
#include <linux/spinlock.h>
#include <asm/atomic.h>
struct super_block;
struct vfsmount;
struct dentry;
struct namespace;
#define MNT_NOSUID 0x01
#define MNT_NODEV 0x02
#define MNT_NOEXEC 0x04
......
......@@ -171,9 +171,9 @@ struct swap_info_struct;
* Deallocate and clear the sb->s_security field.
* @sb contains the super_block structure to be modified.
* @sb_statfs:
* Check permission before obtaining filesystem statistics for the @sb
* filesystem.
* @sb contains the super_block structure for the filesystem.
* Check permission before obtaining filesystem statistics for the @mnt
* mountpoint.
* @dentry is a handle on the superblock for the filesystem.
* Return 0 if permission is granted.
* @sb_mount:
* Check permission before an object specified by @dev_name is mounted on
......@@ -1127,7 +1127,7 @@ struct security_operations {
int (*sb_copy_data)(struct file_system_type *type,
void *orig, void *copy);
int (*sb_kern_mount) (struct super_block *sb, void *data);
int (*sb_statfs) (struct super_block * sb);
int (*sb_statfs) (struct dentry *dentry);
int (*sb_mount) (char *dev_name, struct nameidata * nd,
char *type, unsigned long flags, void *data);
int (*sb_check_sb) (struct vfsmount * mnt, struct nameidata * nd);
......@@ -1450,9 +1450,9 @@ static inline int security_sb_kern_mount (struct super_block *sb, void *data)
return security_ops->sb_kern_mount (sb, data);
}
static inline int security_sb_statfs (struct super_block *sb)
static inline int security_sb_statfs (struct dentry *dentry)
{
return security_ops->sb_statfs (sb);
return security_ops->sb_statfs (dentry);
}
static inline int security_sb_mount (char *dev_name, struct nameidata *nd,
......@@ -2162,7 +2162,7 @@ static inline int security_sb_kern_mount (struct super_block *sb, void *data)
return 0;
}
static inline int security_sb_statfs (struct super_block *sb)
static inline int security_sb_statfs (struct dentry *dentry)
{
return 0;
}
......
......@@ -118,7 +118,7 @@ static int check_free_space(struct file *file)
spin_unlock(&acct_globals.lock);
/* May block */
if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf))
if (vfs_statfs(file->f_dentry, &sbuf))
return res;
suspend = sbuf.f_blocks * SUSPEND;
resume = sbuf.f_blocks * RESUME;
......
......@@ -1654,9 +1654,9 @@ static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
return desc.error;
}
static int shmem_statfs(struct super_block *sb, struct kstatfs *buf)
static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
buf->f_type = TMPFS_MAGIC;
buf->f_bsize = PAGE_CACHE_SIZE;
......
......@@ -191,7 +191,7 @@ static int dummy_sb_kern_mount (struct super_block *sb, void *data)
return 0;
}
static int dummy_sb_statfs (struct super_block *sb)
static int dummy_sb_statfs (struct dentry *dentry)
{
return 0;
}
......
......@@ -1903,13 +1903,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
}
static int selinux_sb_statfs(struct super_block *sb)
static int selinux_sb_statfs(struct dentry *dentry)
{
struct avc_audit_data ad;
AVC_AUDIT_DATA_INIT(&ad,FS);
ad.u.fs.dentry = sb->s_root;
return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad);
ad.u.fs.dentry = dentry->d_sb->s_root;
return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}
static int selinux_mount(char * dev_name,
......
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