From 266239fe645b433a8f6b15814a806664f34cc06b Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Tue, 20 Aug 2013 01:39:47 +0200 Subject: [PATCH] Implement support for getvfsstat(2) Change-Id: I99b697919d411c57105de561105beefc7d1d309a --- distrib/sets/lists/minix/mi | 1 + include/minix/callnr.h | 1 + include/minix/com.h | 5 + include/minix/sysinfo.h | 1 - lib/libc/include/namespace.h | 1 + lib/libc/sys-minix/MISSING_SYSCALLS | 1 - lib/libc/sys-minix/Makefile.inc | 1 + lib/libc/sys-minix/getvfsstat.c | 19 ++++ lib/libc/sys/Makefile.inc | 4 +- lib/libminc/Makefile | 4 +- servers/pm/table.c | 2 +- servers/procfs/Makefile | 2 +- servers/procfs/mounts.c | 34 ------- servers/procfs/mounts.h | 6 -- servers/procfs/root.c | 20 +++- servers/vfs/README | 11 +- servers/vfs/comm.h | 12 --- servers/vfs/fs.h | 2 +- servers/vfs/misc.c | 5 - servers/vfs/mount.c | 11 ++ servers/vfs/proto.h | 2 + servers/vfs/stadir.c | 153 ++++++++++++++++++++++++++-- servers/vfs/table.c | 2 +- servers/vfs/type.h | 41 ++++++++ servers/vfs/vmnt.h | 4 +- sys/sys/statvfs.h | 4 + 26 files changed, 264 insertions(+), 85 deletions(-) create mode 100644 lib/libc/sys-minix/getvfsstat.c delete mode 100644 servers/procfs/mounts.c delete mode 100644 servers/procfs/mounts.h delete mode 100644 servers/vfs/comm.h create mode 100644 servers/vfs/type.h diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 62c5dc3e9..3ab7dc0ec 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -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 diff --git a/include/minix/callnr.h b/include/minix/callnr.h index db2372e2f..69685decb 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -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 */ diff --git a/include/minix/com.h b/include/minix/com.h index a38bbb2d5..8ad57eea1 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -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 diff --git a/include/minix/sysinfo.h b/include/minix/sysinfo.h index 88f9d6fcf..e63bb006e 100644 --- a/include/minix/sysinfo.h +++ b/include/minix/sysinfo.h @@ -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 diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index f7627610f..3a1f9faac 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -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 diff --git a/lib/libc/sys-minix/MISSING_SYSCALLS b/lib/libc/sys-minix/MISSING_SYSCALLS index 98ee058c0..2d50827e7 100644 --- a/lib/libc/sys-minix/MISSING_SYSCALLS +++ b/lib/libc/sys-minix/MISSING_SYSCALLS @@ -14,7 +14,6 @@ getpgid setrlimit getrusage getsid -getvfsstat issetugid /* WARNING: Always returns 0 in this impl. */ kevent kqueue diff --git a/lib/libc/sys-minix/Makefile.inc b/lib/libc/sys-minix/Makefile.inc index 890b66d87..38ef33de8 100644 --- a/lib/libc/sys-minix/Makefile.inc +++ b/lib/libc/sys-minix/Makefile.inc @@ -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 \ diff --git a/lib/libc/sys-minix/getvfsstat.c b/lib/libc/sys-minix/getvfsstat.c new file mode 100644 index 000000000..69a086496 --- /dev/null +++ b/lib/libc/sys-minix/getvfsstat.c @@ -0,0 +1,19 @@ +#include +#include +#include "namespace.h" + +#include + +#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)); +} diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 2fa88dfd5..239ff1aea 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -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 \ diff --git a/lib/libminc/Makefile b/lib/libminc/Makefile index 35e644d8d..18da0cf02 100644 --- a/lib/libminc/Makefile +++ b/lib/libminc/Makefile @@ -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 diff --git a/servers/pm/table.c b/servers/pm/table.c index 6873ff2b7..8660b5449 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -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) */ diff --git a/servers/procfs/Makefile b/servers/procfs/Makefile index 52d79cbbe..cd426ebc6 100644 --- a/servers/procfs/Makefile +++ b/servers/procfs/Makefile @@ -4,7 +4,7 @@ .include 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 diff --git a/servers/procfs/mounts.c b/servers/procfs/mounts.c deleted file mode 100644 index cfd4f2663..000000000 --- a/servers/procfs/mounts.c +++ /dev/null @@ -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"); - } -} diff --git a/servers/procfs/mounts.h b/servers/procfs/mounts.h deleted file mode 100644 index ca5712b4b..000000000 --- a/servers/procfs/mounts.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __PROCFS_MOUNTS_H -#define __PROCFS_MOUNTS_H__ - -void root_mounts(void); - -#endif /* __PROCFS_MOUNTS_H__ */ diff --git a/servers/procfs/root.c b/servers/procfs/root.c index 7629c0ad6..6f121a844 100644 --- a/servers/procfs/root.c +++ b/servers/procfs/root.c @@ -7,7 +7,6 @@ #endif #include #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"); + } +} diff --git a/servers/vfs/README b/servers/vfs/README index bb9751a59..76b675c0d 100644 --- a/servers/vfs/README +++ b/servers/vfs/README @@ -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 diff --git a/servers/vfs/comm.h b/servers/vfs/comm.h deleted file mode 100644 index 4e0d00cc3..000000000 --- a/servers/vfs/comm.h +++ /dev/null @@ -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 diff --git a/servers/vfs/fs.h b/servers/vfs/fs.h index 3c95e26d5..a96a88943 100644 --- a/servers/vfs/fs.h +++ b/servers/vfs/fs.h @@ -28,7 +28,7 @@ #include "proto.h" #include "threads.h" #include "glo.h" -#include "comm.h" +#include "type.h" #include "vmnt.h" #endif diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index f557bd5e8..e30f80084 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -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); } diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 5b25ebe16..da00663a5 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -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); diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index b4d57037b..0c5549e38 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -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 *); diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 138fe06f6..ab718c7dd 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -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" @@ -208,24 +209,87 @@ int do_fstat(message *UNUSED(m_out)) return(r); } +/*===========================================================================* + * update_statvfs * + *===========================================================================*/ +int update_statvfs(struct vmnt *vmp, struct statvfs *buf) +{ +/* Get statistics from a file system, and cache part of the results. */ + int r; + + 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 vnode *vp, endpoint_t endpt, vir_bytes buf_addr) +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 (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. + * 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; - struct vmnt *vmp; - int r; - vmp = vp->v_vmnt; + 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)); - if ((r = req_statvfs(vp->v_fs_e, &buf)) != OK) - return r; + 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 * *===========================================================================*/ diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 3492aae38..5afc110af 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -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 */ diff --git a/servers/vfs/type.h b/servers/vfs/type.h new file mode 100644 index 000000000..673be5f1f --- /dev/null +++ b/servers/vfs/type.h @@ -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 diff --git a/servers/vfs/vmnt.h b/servers/vfs/vmnt.h index a49792c4f..16e7c955d 100644 --- a/servers/vfs/vmnt.h +++ b/servers/vfs/vmnt.h @@ -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 diff --git a/sys/sys/statvfs.h b/sys/sys/statvfs.h index c1cd4df6a..8809c6409 100644 --- a/sys/sys/statvfs.h +++ b/sys/sys/statvfs.h @@ -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_ */ -- 2.44.0