Implement support for getvfsstat(2)

Change-Id: I99b697919d411c57105de561105beefc7d1d309a
This commit is contained in:
David van Moolenbroek 2013-08-20 01:39:47 +02:00 committed by Lionel Sambuc
parent 7113bcb896
commit 266239fe64
26 changed files with 267 additions and 88 deletions

View file

@ -2228,6 +2228,7 @@
./usr/man/man2/getsockopt.2 minix-sys
./usr/man/man2/gettimeofday.2 minix-sys
./usr/man/man2/getuid.2 minix-sys
./usr/man/man2/getvfsstat.2 minix-sys
./usr/man/man2/intro.2 minix-sys
./usr/man/man2/ioctl.2 minix-sys
./usr/man/man2/kill.2 minix-sys

View file

@ -74,6 +74,7 @@
#define SYSUNAME 78
#define GETDENTS_321 80 /* to VFS */
#define LLSEEK 81 /* to VFS */
#define GETVFSSTAT 82 /* to VFS */
#define STATVFS 83 /* to VFS */
#define FSTATVFS 84 /* to VFS */
#define SELECT 85 /* to VFS */

View file

@ -902,6 +902,11 @@
#define SEL_ERRORFDS m8_p3
#define SEL_TIMEOUT m8_p4
/* Field names for the getvfsstat(2) call. */
#define VFS_GETVFSSTAT_BUF m1_p1
#define VFS_GETVFSSTAT_SIZE m1_i1
#define VFS_GETVFSSTAT_FLAGS m1_i2
/* Field names for the fstatvfs call */
#define FSTATVFS_FD m1_i1
#define FSTATVFS_BUF m1_p1

View file

@ -13,7 +13,6 @@ int getsysinfo(endpoint_t who, int what, void *where, size_t size);
#define SI_DATA_STORE 5 /* get copy of data store mappings */
#define SI_CALL_STATS 9 /* system call statistics */
#define SI_PROCPUB_TAB 11 /* copy of public entries of process table */
#define SI_VMNT_TAB 12 /* get vmnt table */
#endif

View file

@ -366,6 +366,7 @@
#define getttyent _getttyent
#define getttynam _getttynam
#define getusershell _getusershell
#define getvfsstat _getvfsstat
#define glob _glob
#define globfree _globfree
#define gmtime_r _gmtime_r

View file

@ -14,7 +14,6 @@ getpgid
setrlimit
getrusage
getsid
getvfsstat
issetugid /* WARNING: Always returns 0 in this impl. */
kevent
kqueue

View file

@ -8,6 +8,7 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
getgroups.c getitimer.c setitimer.c __getlogin.c getpeername.c \
getpgrp.c getpid.c getppid.c priority.c getrlimit.c getsockname.c \
getsockopt.c setsockopt.c gettimeofday.c geteuid.c getuid.c \
getvfsstat.c \
ioctl.c issetugid.c kill.c link.c listen.c loadname.c lseek.c \
minix_rs.c mkdir.c mkfifo.c mknod.c mmap.c mount.c nanosleep.c \
open.c pathconf.c pipe.c poll.c pread.c ptrace.c pwrite.c \

View file

@ -0,0 +1,19 @@
#include <sys/cdefs.h>
#include <lib.h>
#include "namespace.h"
#include <sys/statvfs.h>
#ifdef __weak_alias
__weak_alias(getvfsstat, _getvfsstat)
#endif
int getvfsstat(struct statvfs *buf, size_t bufsize, int flags)
{
message m;
m.VFS_GETVFSSTAT_BUF = (char *) buf;
m.VFS_GETVFSSTAT_SIZE = bufsize;
m.VFS_GETVFSSTAT_FLAGS = flags;
return(_syscall(VFS_PROC_NR, GETVFSSTAT, &m));
}

View file

@ -226,7 +226,7 @@ MAN+= accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \
connect.2 dup.2 execve.2 _exit.2 extattr_get_file.2 \
fcntl.2 fdatasync.2 fhopen.2 \
flock.2 fork.2 fsync.2 getcontext.2 getdents.2 \
getfh.2 getvfsstat.2 getgid.2 getgroups.2 \
getfh.2 getgid.2 getgroups.2 \
getitimer.2 getlogin.2 getpeername.2 getpgrp.2 getpid.2 \
getpriority.2 getrlimit.2 getsid.2 getsockname.2 \
getsockopt.2 gettimeofday.2 getuid.2 intro.2 ioctl.2 issetugid.2 \
@ -244,7 +244,7 @@ MAN+= accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \
mprotect.2 mremap.2 msgctl.2 msgget.2 msgrcv.2 msgsnd.2 msync.2 \
munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 pathconf.2 pipe.2
.else
MAN+= adjtime.2 clock_settime.2 pipe.2 getrusage.2
MAN+= adjtime.2 clock_settime.2 getvfsstat.2 pipe.2 getrusage.2
.endif # !defined(__MINIX)
.if !defined(__MINIX)
MAN+= pmc_control.2 poll.2 posix_fadvise.2 profil.2 ptrace.2 __quotactl.2 \

View file

@ -144,8 +144,8 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale
# Import from sys-minix
.for i in access.c brk.c close.c environ.c execve.c fork.c \
getgid.c getpid.c geteuid.c getuid.c gettimeofday.c loadname.c \
link.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \
getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \
link.c loadname.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \
read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stat.c \
stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \
brksize.S _ipc.S _senda.S ucontext.S mmap.c init.c

View file

@ -93,7 +93,7 @@ int (*call_vec[])(void) = {
no_sys, /* 79 = unused */
no_sys, /* 80 = (getdents) */
no_sys, /* 81 = unused */
no_sys, /* 82 = unused */
no_sys, /* 82 = (getvfsstat) */
no_sys, /* 83 = unused */
no_sys, /* 84 = unused */
no_sys, /* 85 = (select) */

View file

@ -4,7 +4,7 @@
.include <bsd.own.mk>
PROG= procfs
SRCS= buf.c main.c pid.c root.c tree.c util.c cpuinfo.c mounts.c
SRCS= buf.c main.c pid.c root.c tree.c util.c cpuinfo.c
CPPFLAGS+= -I${NETBSDSRCDIR} -I${NETBSDSRCDIR}/servers

View file

@ -1,34 +0,0 @@
#include "inc.h"
#include "vfs/vmnt.h"
extern struct mproc mproc[NR_PROCS];
/*===========================================================================*
* root_mtab *
*===========================================================================*/
void
root_mounts(void)
{
struct vmnt vmnt[NR_MNTS];
struct vmnt *vmp;
struct mproc *rmp;
int slot;
if (getsysinfo(VFS_PROC_NR, SI_VMNT_TAB, vmnt, sizeof(vmnt)) != OK)
return;
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
if (vmp->m_dev == NO_DEV)
continue;
if (vmp->m_fs_e == PFS_PROC_NR)
continue; /* Skip (special case) */
slot = _ENDPOINT_P(vmp->m_fs_e);
if (slot < 0 || slot >= NR_PROCS)
continue;
rmp = &mproc[slot];
buf_printf("%s on %s type %s (%s)\n", vmp->m_mount_dev,
vmp->m_mount_path, rmp->mp_name,
(vmp->m_flags & VMNT_READONLY) ? "ro" : "rw");
}
}

View file

@ -1,6 +0,0 @@
#ifndef __PROCFS_MOUNTS_H
#define __PROCFS_MOUNTS_H__
void root_mounts(void);
#endif /* __PROCFS_MOUNTS_H__ */

View file

@ -7,7 +7,6 @@
#endif
#include <minix/dmap.h>
#include "cpuinfo.h"
#include "mounts.h"
static void root_hz(void);
static void root_uptime(void);
@ -19,6 +18,7 @@ static void root_pci(void);
#endif
static void root_dmap(void);
static void root_ipcvecs(void);
static void root_mounts(void);
struct file root_files[] = {
{ "hz", REG_ALL_MODE, (data_t) root_hz },
@ -209,3 +209,21 @@ static void root_ipcvecs(void)
PRINT_ENTRYPOINT(do_kernel_call);
}
/*===========================================================================*
* root_mounts *
*===========================================================================*/
static void
root_mounts(void)
{
struct statvfs buf[NR_MNTS];
int i, count;
if ((count = getvfsstat(buf, sizeof(buf), ST_NOWAIT)) < 0)
return;
for (i = 0; i < count; i++) {
buf_printf("%s on %s type %s (%s)\n", buf[i].f_mntfromname,
buf[i].f_mntonname, buf[i].f_fstypename,
(buf[i].f_flag & ST_RDONLY) ? "ro" : "rw");
}
}

View file

@ -38,7 +38,7 @@ it supports a few calls necessary for libc. The following system calls are
handled by VFS:
access, chdir, chmod, chown, chroot, close, creat, fchdir, fcntl, fstat,
fstatvfs, fsync, ftruncate getdents, ioctl, link, llseek, lseek,
fstatvfs, fsync, ftruncate, getdents, getvfsstat, ioctl, link, llseek, lseek,
lstat, mkdir, mknod, mount, open, pipe, read, readlink, rename, rmdir, select,
stat, statvfs, symlink, sync, truncate, umask, umount, unlink, utime, write.
@ -355,7 +355,7 @@ requests) do need a vmnt lock.
| a file descriptor | getdents, ioctl, llseek, pipe, read, select, write |
| argument | |
+-------------------+---------------------------------------------------------+
| System calls with | fsync++, sync, umask |
| System calls with | fsync++, getvfsstat, sync, umask |
| other or no | |
| arguments | |
-------------------------------------------------------------------------------
@ -452,11 +452,12 @@ as used by VFS.
| File rename | rename | VMNT_EXCL | Identical to file unlink |
| ops. | | | operations |
+-------------+--------------+------------+-----------------------------------+
| Non-file | sync, umask | VMNT_READ | umask does not involve the file |
| ops. | | or none | system, so it does not need |
| Non-file | sync, umask, | VMNT_READ | umask does not involve the file |
| ops. | getvfsstat | or none | system, so it does not need |
| | | | locks. sync does not alter state |
| | | | in VFS and is atomic at the FS |
| | | | level |
| | | | level. getvfsstat caches stats |
| | | | only and requires no exclusion. |
-------------------------------------------------------------------------------
}}}
Table 5: System call without file descriptor argument sub-categorization

View file

@ -1,12 +0,0 @@
#ifndef __VFS_COMM_H__
#define __VFS_COMM_H__
/* VFS<->FS communication */
typedef struct {
int c_max_reqs; /* Max requests an FS can handle simultaneously */
int c_cur_reqs; /* Number of requests the FS is currently handling */
struct worker_thread *c_req_queue;/* Queue of procs waiting to send a message */
} comm_t;
#endif

View file

@ -28,7 +28,7 @@
#include "proto.h"
#include "threads.h"
#include "glo.h"
#include "comm.h"
#include "type.h"
#include "vmnt.h"
#endif

View file

@ -91,11 +91,6 @@ int do_getsysinfo()
len = sizeof(calls_stats);
break;
#endif
case SI_VMNT_TAB:
fetch_vmnt_paths();
src_addr = (vir_bytes) vmnt;
len = sizeof(struct vmnt) * NR_MNTS;
break;
default:
return(EINVAL);
}

View file

@ -183,6 +183,7 @@ char mount_label[LABEL_MAX] )
char *label;
struct node_details res;
struct lookup resolve;
struct statvfs statvfs_buf;
/* Look up block device driver label when dev is not a pseudo-device */
label = "";
@ -290,6 +291,10 @@ char mount_label[LABEL_MAX] )
new_vmp->m_haspeek = 1;
}
/* Fill the statvfs cache with initial values. */
if (r == OK)
r = update_statvfs(new_vmp, &statvfs_buf);
if (r != OK) {
mark_vmnt_free(new_vmp);
unlock_vnode(root_node);
@ -323,6 +328,9 @@ char mount_label[LABEL_MAX] )
new_vmp->m_comm.c_max_reqs = VFS_FS_PROTO_CONREQS(new_vmp->m_proto);
new_vmp->m_comm.c_cur_reqs = 0;
/* No more blocking operations, so we can now report on this file system. */
new_vmp->m_flags |= VMNT_CANSTAT;
if (mount_root) {
/* Superblock and root node already read.
* Nothing else can go wrong. Perform the mount. */
@ -501,6 +509,9 @@ int unmount(
return(EBUSY); /* can't umount a busy file system */
}
/* This FS will now disappear, so stop listing it in statistics. */
vmp->m_flags &= ~VMNT_CANSTAT;
/* Tell FS to drop all inode references for root inode except 1. */
vnode_clean_refs(vmp->m_root_node);

View file

@ -287,8 +287,10 @@ int do_fstat(message *m_out);
int do_stat(message *m_out);
int do_statvfs(message *m_out);
int do_fstatvfs(message *m_out);
int do_getvfsstat(message *m_out);
int do_rdlink(message *m_out);
int do_lstat(message *m_out);
int update_statvfs(struct vmnt *vmp, struct statvfs *buf);
/* time.c */
int do_utime(message *);

View file

@ -9,6 +9,7 @@
* do_fstat: perform the FSTAT system call
* do_statvfs: perform the STATVFS system call
* do_fstatvfs: perform the FSTATVFS system call
* do_getvfsstat: perform the GETVFSSTAT system call
*/
#include "fs.h"
@ -209,24 +210,87 @@ int do_fstat(message *UNUSED(m_out))
}
/*===========================================================================*
* fill_statvfs *
* update_statvfs *
*===========================================================================*/
static int fill_statvfs(struct vnode *vp, endpoint_t endpt, vir_bytes buf_addr)
int update_statvfs(struct vmnt *vmp, struct statvfs *buf)
{
/* Fill a statvfs structure in a userspace process. First let the target file
* server (as identified by the given vnode) fill in most fields. Then fill in
* some remaining fields with local information. Finally, copy the result to
* user space.
*/
struct statvfs buf;
struct vmnt *vmp;
/* Get statistics from a file system, and cache part of the results. */
int r;
vmp = vp->v_vmnt;
if ((r = req_statvfs(vp->v_fs_e, &buf)) != OK)
if ((r = req_statvfs(vmp->m_fs_e, buf)) != OK)
return r;
vmp->m_stats.f_flag = buf->f_flag;
vmp->m_stats.f_bsize = buf->f_bsize;
vmp->m_stats.f_frsize = buf->f_frsize;
vmp->m_stats.f_iosize = buf->f_iosize;
vmp->m_stats.f_blocks = buf->f_blocks;
vmp->m_stats.f_bfree = buf->f_bfree;
vmp->m_stats.f_bavail = buf->f_bavail;
vmp->m_stats.f_bresvd = buf->f_bresvd;
vmp->m_stats.f_files = buf->f_files;
vmp->m_stats.f_ffree = buf->f_ffree;
vmp->m_stats.f_favail = buf->f_favail;
vmp->m_stats.f_fresvd = buf->f_fresvd;
vmp->m_stats.f_syncreads = buf->f_syncreads;
vmp->m_stats.f_syncwrites = buf->f_syncwrites;
vmp->m_stats.f_asyncreads = buf->f_asyncreads;
vmp->m_stats.f_asyncwrites = buf->f_asyncwrites;
vmp->m_stats.f_namemax = buf->f_namemax;
return OK;
}
/*===========================================================================*
* fill_statvfs *
*===========================================================================*/
static int fill_statvfs(struct vmnt *vmp, endpoint_t endpt, vir_bytes buf_addr,
int flags)
{
/* Fill a statvfs structure in a userspace process. First let the target file
* server fill in most fields, or use the cached copy if ST_NOWAIT is given.
* Then fill in some remaining fields with local information. Finally, copy
* the result to user space.
*/
struct statvfs buf;
if (!(flags & ST_NOWAIT)) {
/* Get fresh statistics from the file system. */
if (update_statvfs(vmp, &buf) != OK)
return EIO;
} else {
/* Use the cached statistics. */
memset(&buf, 0, sizeof(buf));
buf.f_flag = vmp->m_stats.f_flag;
buf.f_bsize = vmp->m_stats.f_bsize;
buf.f_frsize = vmp->m_stats.f_frsize;
buf.f_iosize = vmp->m_stats.f_iosize;
buf.f_blocks = vmp->m_stats.f_blocks;
buf.f_bfree = vmp->m_stats.f_bfree;
buf.f_bavail = vmp->m_stats.f_bavail;
buf.f_bresvd = vmp->m_stats.f_bresvd;
buf.f_files = vmp->m_stats.f_files;
buf.f_ffree = vmp->m_stats.f_ffree;
buf.f_favail = vmp->m_stats.f_favail;
buf.f_fresvd = vmp->m_stats.f_fresvd;
buf.f_syncreads = vmp->m_stats.f_syncreads;
buf.f_syncwrites = vmp->m_stats.f_syncwrites;
buf.f_asyncreads = vmp->m_stats.f_asyncreads;
buf.f_asyncwrites = vmp->m_stats.f_asyncwrites;
buf.f_namemax = vmp->m_stats.f_namemax;
}
if (vmp->m_flags & VMNT_READONLY)
buf.f_flag |= ST_RDONLY;
@ -265,7 +329,7 @@ int do_statvfs(message *UNUSED(m_out))
if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code);
r = fill_statvfs(vp, who_e, statbuf);
r = fill_statvfs(vp->v_vmnt, who_e, statbuf, ST_WAIT);
unlock_vnode(vp);
unlock_vmnt(vmp);
@ -289,13 +353,80 @@ int do_fstatvfs(message *UNUSED(m_out))
/* Is the file descriptor valid? */
if ((rfilp = get_filp(rfd, VNODE_READ)) == NULL) return(err_code);
r = fill_statvfs(rfilp->filp_vno, who_e, statbuf);
r = fill_statvfs(rfilp->filp_vno->v_vmnt, who_e, statbuf, ST_WAIT);
unlock_filp(rfilp);
return(r);
}
/*===========================================================================*
* do_getvfsstat *
*===========================================================================*/
int do_getvfsstat(message *UNUSED(m_out))
{
/* Perform the getvfsstat(buf, bufsize, flags) system call. */
struct vmnt *vmp;
vir_bytes buf;
size_t bufsize;
int r, flags, count, do_lock;
buf = (vir_bytes) job_m_in.VFS_GETVFSSTAT_BUF;
bufsize = job_m_in.VFS_GETVFSSTAT_SIZE;
flags = job_m_in.VFS_GETVFSSTAT_FLAGS;
count = 0;
if (buf != 0) {
/* We only need to lock target file systems if we are going to query
* them. This will only happen if ST_NOWAIT is not given. If we do
* not lock, we rely on the VMNT_CANSTAT flag to protect us from
* concurrent (un)mount operations. Note that procfs relies on
* ST_NOWAIT calls being lock free, as it is a file system itself.
*/
do_lock = !(flags & ST_NOWAIT);
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
/* If there is no more space, return the count so far. */
if (bufsize < sizeof(struct statvfs))
break;
/* Lock the file system before checking any fields. */
if (do_lock && (r = lock_vmnt(vmp, VMNT_READ)) != OK)
return r;
/* Obtain information for this file system, if it is in use and
* can be reported. File systems that are being (un)mounted
* are skipped, as is PFS. The fill call will block only if
* ST_NOWAIT was not given.
*/
if (vmp->m_dev != NO_DEV && (vmp->m_flags & VMNT_CANSTAT)) {
if ((r = fill_statvfs(vmp, who_e, buf, flags)) != OK) {
if (do_lock)
unlock_vmnt(vmp);
return r;
}
count++;
buf += sizeof(struct statvfs);
bufsize -= sizeof(struct statvfs);
}
if (do_lock)
unlock_vmnt(vmp);
}
} else {
/* Just report a file system count. No need to lock, as above. */
for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) {
if (vmp->m_dev != NO_DEV && (vmp->m_flags & VMNT_CANSTAT))
count++;
}
}
return count;
}
/*===========================================================================*
* do_lstat *
*===========================================================================*/

View file

@ -97,7 +97,7 @@ int (*call_vec[])(message *m_out) = {
no_sys, /* 79 = unused */
do_getdents, /* 80 = getdents_321 (to be phased out) */
do_lseek, /* 81 = llseek */
no_sys, /* 82 = unused */
do_getvfsstat, /* 82 = getvfsstat */
do_statvfs, /* 83 = fstatvfs */
do_fstatvfs, /* 84 = statvfs */
do_select, /* 85 = select */

41
servers/vfs/type.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef __VFS_TYPE_H__
#define __VFS_TYPE_H__
/* VFS<->FS communication */
typedef struct {
int c_max_reqs; /* Max requests an FS can handle simultaneously */
int c_cur_reqs; /* Number of requests the FS is currently handling */
struct worker_thread *c_req_queue;/* Queue of procs waiting to send a message */
} comm_t;
/*
* Cached statvfs fields. We are not using struct statvfs itself because that
* would add over 2K of unused memory per mount table entry.
*/
struct statvfs_cache {
unsigned long f_flag; /* copy of mount exported flags */
unsigned long f_bsize; /* file system block size */
unsigned long f_frsize; /* fundamental file system block size */
unsigned long f_iosize; /* optimal file system block size */
fsblkcnt_t f_blocks; /* number of blocks in file system, */
fsblkcnt_t f_bfree; /* free blocks avail in file system */
fsblkcnt_t f_bavail; /* free blocks avail to non-root */
fsblkcnt_t f_bresvd; /* blocks reserved for root */
fsfilcnt_t f_files; /* total file nodes in file system */
fsfilcnt_t f_ffree; /* free file nodes in file system */
fsfilcnt_t f_favail; /* free file nodes avail to non-root */
fsfilcnt_t f_fresvd; /* file nodes reserved for root */
uint64_t f_syncreads; /* count of sync reads since mount */
uint64_t f_syncwrites; /* count of sync writes since mount */
uint64_t f_asyncreads; /* count of async reads since mount */
uint64_t f_asyncwrites; /* count of async writes since mount */
unsigned long f_namemax; /* maximum filename length */
};
#endif

View file

@ -2,7 +2,7 @@
#define __VFS_VMNT_H__
#include "tll.h"
#include "comm.h"
#include "type.h"
EXTERN struct vmnt {
int m_fs_e; /* FS process' kernel endpoint */
@ -18,6 +18,7 @@ EXTERN struct vmnt {
char m_mount_dev[PATH_MAX]; /* device from which vmnt is mounted */
char m_fstype[FSTYPE_MAX]; /* file system type */
int m_haspeek; /* supports REQ_PEEK, REQ_BPEEK */
struct statvfs_cache m_stats; /* cached file system statistics */
} vmnt[NR_MNTS];
/* vmnt flags */
@ -25,6 +26,7 @@ EXTERN struct vmnt {
#define VMNT_CALLBACK 02 /* FS did back call */
#define VMNT_MOUNTING 04 /* Device is being mounted */
#define VMNT_FORCEROOTBSF 010 /* Force usage of none-device */
#define VMNT_CANSTAT 020 /* Include FS in getvfsstat output */
/* vmnt lock types mapping */
#define VMNT_READ TLL_READ

View file

@ -111,9 +111,13 @@ struct statvfs {
#define ST_NOTRUNC __MNT_UNUSED1
#endif /* !__minix*/
#define ST_WAIT MNT_WAIT
#define ST_NOWAIT MNT_NOWAIT
__BEGIN_DECLS
int statvfs(const char *__restrict, struct statvfs *__restrict);
int fstatvfs(int, struct statvfs *);
int getvfsstat(struct statvfs *, size_t, int);
__END_DECLS
#endif /* !_SYS_STATVFS_H_ */