Home | History | Annotate | Line # | Download | only in chfs
chfs_subr.c revision 1.15
      1  1.15  riastrad /*	$NetBSD: chfs_subr.c,v 1.15 2020/09/05 16:30:12 riastradh Exp $	*/
      2   1.1     ahoka 
      3   1.1     ahoka /*-
      4   1.1     ahoka  * Copyright (c) 2010 Department of Software Engineering,
      5   1.1     ahoka  *		      University of Szeged, Hungary
      6   1.1     ahoka  * Copyright (C) 2010 Tamas Toth <ttoth (at) inf.u-szeged.hu>
      7   1.1     ahoka  * Copyright (C) 2010 Adam Hoka <ahoka (at) NetBSD.org>
      8   1.1     ahoka  * All rights reserved.
      9   1.1     ahoka  *
     10   1.1     ahoka  * This code is derived from software contributed to The NetBSD Foundation
     11   1.1     ahoka  * by the Department of Software Engineering, University of Szeged, Hungary
     12   1.1     ahoka  *
     13   1.1     ahoka  * Redistribution and use in source and binary forms, with or without
     14   1.1     ahoka  * modification, are permitted provided that the following conditions
     15   1.1     ahoka  * are met:
     16   1.1     ahoka  * 1. Redistributions of source code must retain the above copyright
     17   1.1     ahoka  *    notice, this list of conditions and the following disclaimer.
     18   1.1     ahoka  * 2. Redistributions in binary form must reproduce the above copyright
     19   1.1     ahoka  *    notice, this list of conditions and the following disclaimer in the
     20   1.1     ahoka  *    documentation and/or other materials provided with the distribution.
     21   1.1     ahoka  *
     22   1.1     ahoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23   1.1     ahoka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24   1.1     ahoka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25   1.1     ahoka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26   1.1     ahoka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     27   1.1     ahoka  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     28   1.1     ahoka  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     29   1.1     ahoka  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     30   1.1     ahoka  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1     ahoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1     ahoka  * SUCH DAMAGE.
     33   1.1     ahoka  */
     34   1.1     ahoka 
     35   1.1     ahoka #include <sys/cdefs.h>
     36   1.1     ahoka 
     37   1.1     ahoka #include <sys/param.h>
     38   1.1     ahoka #include <sys/dirent.h>
     39   1.1     ahoka #include <sys/event.h>
     40   1.1     ahoka #include <sys/kmem.h>
     41   1.1     ahoka #include <sys/mount.h>
     42   1.1     ahoka #include <sys/namei.h>
     43   1.1     ahoka #include <sys/time.h>
     44   1.1     ahoka #include <sys/stat.h>
     45   1.1     ahoka #include <sys/systm.h>
     46   1.1     ahoka #include <sys/swap.h>
     47   1.1     ahoka #include <sys/vnode.h>
     48   1.1     ahoka #include <sys/kauth.h>
     49   1.1     ahoka #include <sys/proc.h>
     50   1.1     ahoka #include <sys/atomic.h>
     51   1.1     ahoka 
     52  1.15  riastrad #include <uvm/uvm_extern.h>
     53   1.1     ahoka 
     54   1.1     ahoka #include <miscfs/specfs/specdev.h>
     55   1.3      elad #include <miscfs/genfs/genfs.h>
     56   1.1     ahoka #include "chfs.h"
     57   1.1     ahoka 
     58   1.1     ahoka 
     59   1.1     ahoka /*
     60   1.8     ttoth  * chfs_mem_info -
     61   1.1     ahoka  * Returns information about the number of available memory pages,
     62   1.1     ahoka  * including physical and virtual ones.
     63   1.1     ahoka  *
     64   1.1     ahoka  * If 'total' is true, the value returned is the total amount of memory
     65   1.1     ahoka  * pages configured for the system (either in use or free).
     66   1.1     ahoka  * If it is FALSE, the value returned is the amount of free memory pages.
     67   1.1     ahoka  *
     68   1.1     ahoka  * Remember to remove DUMMYFS_PAGES_RESERVED from the returned value to avoid
     69   1.1     ahoka  * excessive memory usage.
     70   1.1     ahoka  *
     71   1.1     ahoka  */
     72   1.1     ahoka size_t
     73   1.1     ahoka chfs_mem_info(bool total)
     74   1.1     ahoka {
     75   1.1     ahoka 	size_t size;
     76   1.1     ahoka 
     77   1.1     ahoka 	size = 0;
     78   1.1     ahoka 	size += uvmexp.swpgavail;
     79   1.1     ahoka 	if (!total) {
     80   1.1     ahoka 		size -= uvmexp.swpgonly;
     81   1.1     ahoka 	}
     82  1.14        ad 	size += uvm_availmem(true);
     83   1.1     ahoka 	size += uvmexp.filepages;
     84   1.1     ahoka 	if (size > uvmexp.wired) {
     85   1.1     ahoka 		size -= uvmexp.wired;
     86   1.1     ahoka 	} else {
     87   1.1     ahoka 		size = 0;
     88   1.1     ahoka 	}
     89   1.1     ahoka 
     90   1.1     ahoka 	return size;
     91   1.1     ahoka }
     92   1.1     ahoka 
     93   1.1     ahoka 
     94   1.1     ahoka /*
     95   1.8     ttoth  * chfs_dir_lookup -
     96   1.1     ahoka  * Looks for a directory entry in the directory represented by node.
     97   1.1     ahoka  * 'cnp' describes the name of the entry to look for.  Note that the .
     98   1.1     ahoka  * and .. components are not allowed as they do not physically exist
     99   1.1     ahoka  * within directories.
    100   1.1     ahoka  *
    101   1.1     ahoka  * Returns a pointer to the entry when found, otherwise NULL.
    102   1.1     ahoka  */
    103   1.1     ahoka struct chfs_dirent *
    104   1.1     ahoka chfs_dir_lookup(struct chfs_inode *ip, struct componentname *cnp)
    105   1.1     ahoka {
    106   1.1     ahoka 	bool found;
    107   1.1     ahoka 	struct chfs_dirent *fd;
    108   1.1     ahoka 	dbg("dir_lookup()\n");
    109   1.1     ahoka 
    110   1.1     ahoka 	KASSERT(IMPLIES(cnp->cn_namelen == 1, cnp->cn_nameptr[0] != '.'));
    111   1.1     ahoka 	KASSERT(IMPLIES(cnp->cn_namelen == 2, !(cnp->cn_nameptr[0] == '.' &&
    112   1.1     ahoka 		    cnp->cn_nameptr[1] == '.')));
    113   1.1     ahoka 
    114   1.1     ahoka 	found = false;
    115   1.1     ahoka 	TAILQ_FOREACH(fd, &ip->dents, fds) {
    116   1.1     ahoka 		KASSERT(cnp->cn_namelen < 0xffff);
    117   1.1     ahoka 		if (fd->vno == 0)
    118   1.1     ahoka 			continue;
    119   1.1     ahoka 		if (fd->nsize == (uint16_t)cnp->cn_namelen &&
    120   1.1     ahoka 		    memcmp(fd->name, cnp->cn_nameptr, fd->nsize) == 0) {
    121   1.1     ahoka 			found = true;
    122   1.1     ahoka 			break;
    123   1.1     ahoka 		}
    124   1.1     ahoka 	}
    125   1.1     ahoka 
    126   1.1     ahoka 	return found ? fd : NULL;
    127   1.1     ahoka }
    128   1.1     ahoka 
    129   1.8     ttoth /*
    130   1.8     ttoth  * chfs_filldir -
    131   1.8     ttoth  * Creates a (kernel) dirent and moves it to the given memory address.
    132   1.8     ttoth  * Used during readdir.
    133   1.8     ttoth  */
    134   1.1     ahoka int
    135   1.1     ahoka chfs_filldir(struct uio* uio, ino_t ino, const char *name,
    136   1.4     ttoth     int namelen, enum chtype type)
    137   1.1     ahoka {
    138   1.1     ahoka 	struct dirent dent;
    139   1.1     ahoka 	int error;
    140   1.1     ahoka 
    141   1.1     ahoka 	memset(&dent, 0, sizeof(dent));
    142   1.1     ahoka 
    143   1.1     ahoka 	dent.d_fileno = ino;
    144   1.1     ahoka 	switch (type) {
    145   1.4     ttoth 	case CHT_BLK:
    146   1.1     ahoka 		dent.d_type = DT_BLK;
    147   1.1     ahoka 		break;
    148   1.1     ahoka 
    149   1.4     ttoth 	case CHT_CHR:
    150   1.1     ahoka 		dent.d_type = DT_CHR;
    151   1.1     ahoka 		break;
    152   1.1     ahoka 
    153   1.4     ttoth 	case CHT_DIR:
    154   1.1     ahoka 		dent.d_type = DT_DIR;
    155   1.1     ahoka 		break;
    156   1.1     ahoka 
    157   1.4     ttoth 	case CHT_FIFO:
    158   1.1     ahoka 		dent.d_type = DT_FIFO;
    159   1.1     ahoka 		break;
    160   1.1     ahoka 
    161   1.4     ttoth 	case CHT_LNK:
    162   1.1     ahoka 		dent.d_type = DT_LNK;
    163   1.1     ahoka 		break;
    164   1.1     ahoka 
    165   1.4     ttoth 	case CHT_REG:
    166   1.1     ahoka 		dent.d_type = DT_REG;
    167   1.1     ahoka 		break;
    168   1.1     ahoka 
    169   1.4     ttoth 	case CHT_SOCK:
    170   1.1     ahoka 		dent.d_type = DT_SOCK;
    171   1.1     ahoka 		break;
    172   1.1     ahoka 
    173   1.1     ahoka 	default:
    174   1.1     ahoka 		KASSERT(0);
    175   1.1     ahoka 	}
    176   1.1     ahoka 	dent.d_namlen = namelen;
    177   1.1     ahoka 	(void)memcpy(dent.d_name, name, dent.d_namlen);
    178   1.1     ahoka 	dent.d_reclen = _DIRENT_SIZE(&dent);
    179   1.1     ahoka 
    180   1.1     ahoka 	if (dent.d_reclen > uio->uio_resid) {
    181   1.1     ahoka 		error = -1;
    182   1.1     ahoka 	} else {
    183   1.1     ahoka 		error = uiomove(&dent, dent.d_reclen, uio);
    184   1.1     ahoka 	}
    185   1.1     ahoka 
    186   1.1     ahoka 	return error;
    187   1.1     ahoka }
    188   1.1     ahoka 
    189   1.1     ahoka /*
    190   1.8     ttoth  * chfs_chsize - change size of the given vnode
    191   1.1     ahoka  * Caller should execute chfs_update on vp after a successful execution.
    192   1.1     ahoka  * The vnode must be locked on entry and remain locked on exit.
    193   1.1     ahoka  */
    194   1.1     ahoka int
    195   1.1     ahoka chfs_chsize(struct vnode *vp, u_quad_t size, kauth_cred_t cred)
    196   1.1     ahoka {
    197   1.1     ahoka 	struct chfs_mount *chmp;
    198   1.1     ahoka 	struct chfs_inode *ip;
    199   1.1     ahoka 
    200   1.1     ahoka 	ip = VTOI(vp);
    201   1.1     ahoka 	chmp = ip->chmp;
    202   1.1     ahoka 
    203   1.1     ahoka 	dbg("chfs_chsize\n");
    204   1.1     ahoka 
    205   1.4     ttoth 	switch (ip->ch_type) {
    206   1.4     ttoth 	case CHT_DIR:
    207   1.1     ahoka 		return EISDIR;
    208   1.4     ttoth 	case CHT_LNK:
    209   1.4     ttoth 	case CHT_REG:
    210   1.1     ahoka 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
    211   1.1     ahoka 			return EROFS;
    212   1.1     ahoka 		break;
    213   1.4     ttoth 	case CHT_BLK:
    214   1.4     ttoth 	case CHT_CHR:
    215   1.4     ttoth 	case CHT_FIFO:
    216   1.1     ahoka 		return 0;
    217   1.1     ahoka 	default:
    218   1.1     ahoka 		return EOPNOTSUPP; /* XXX why not ENODEV? */
    219   1.1     ahoka 	}
    220   1.1     ahoka 
    221   1.1     ahoka 	vflushbuf(vp, 0);
    222   1.1     ahoka 
    223   1.1     ahoka 	mutex_enter(&chmp->chm_lock_mountfields);
    224   1.1     ahoka 
    225   1.7     ttoth 	if (ip->size < size) {
    226   1.7     ttoth 		uvm_vnp_setsize(vp, size);
    227   1.1     ahoka 		chfs_set_vnode_size(vp, size);
    228   1.7     ttoth 		ip->iflag |= IN_CHANGE | IN_UPDATE;
    229   1.1     ahoka 
    230   1.1     ahoka 		mutex_exit(&chmp->chm_lock_mountfields);
    231   1.1     ahoka 		return 0;
    232   1.1     ahoka 	}
    233   1.1     ahoka 
    234   1.7     ttoth 	if (size != 0) {
    235  1.12        ad 		ubc_zerorange(&vp->v_uobj, size, ip->size - size, UBC_VNODE_FLAGS(vp));
    236   1.1     ahoka 	}
    237   1.7     ttoth 
    238   1.8     ttoth 	/* drop unused fragments */
    239   1.7     ttoth 	chfs_truncate_fragtree(ip->chmp, &ip->fragtree, size);
    240   1.8     ttoth 
    241   1.7     ttoth 	uvm_vnp_setsize(vp, size);
    242   1.1     ahoka 	chfs_set_vnode_size(vp, size);
    243   1.7     ttoth 	ip->iflag |= IN_CHANGE | IN_UPDATE;
    244   1.1     ahoka 	mutex_exit(&chmp->chm_lock_mountfields);
    245   1.1     ahoka 	return 0;
    246   1.1     ahoka }
    247   1.1     ahoka 
    248   1.1     ahoka /*
    249   1.8     ttoth  * chfs_chflags - change flags of the given vnode
    250   1.1     ahoka  * Caller should execute chfs_update on vp after a successful execution.
    251   1.1     ahoka  * The vnode must be locked on entry and remain locked on exit.
    252   1.1     ahoka  */
    253   1.1     ahoka int
    254   1.1     ahoka chfs_chflags(struct vnode *vp, int flags, kauth_cred_t cred)
    255   1.1     ahoka {
    256   1.1     ahoka 	struct chfs_inode *ip;
    257   1.1     ahoka 	int error = 0;
    258   1.3      elad 	kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
    259   1.3      elad 	bool changing_sysflags = false;
    260   1.1     ahoka 
    261   1.1     ahoka 	ip = VTOI(vp);
    262   1.1     ahoka 
    263   1.1     ahoka 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
    264   1.1     ahoka 		return EROFS;
    265   1.1     ahoka 
    266   1.3      elad 	if ((flags & SF_SNAPSHOT) != (ip->flags & SF_SNAPSHOT))
    267   1.3      elad 		return EPERM;
    268   1.3      elad 
    269   1.3      elad 	/* Indicate we're changing system flags if we are. */
    270   1.3      elad 	if ((ip->flags & SF_SETTABLE) != (flags & SF_SETTABLE) ||
    271   1.3      elad 	    (flags & UF_SETTABLE) != flags) {
    272   1.3      elad 		action |= KAUTH_VNODE_WRITE_SYSFLAGS;
    273   1.3      elad 		changing_sysflags = true;
    274   1.3      elad 	}
    275   1.3      elad 
    276   1.3      elad 	/* Indicate the node has system flags if it does. */
    277   1.3      elad 	if (ip->flags & (SF_IMMUTABLE | SF_APPEND)) {
    278   1.3      elad 		action |= KAUTH_VNODE_HAS_SYSFLAGS;
    279   1.3      elad 	}
    280   1.3      elad 
    281   1.3      elad 	error = kauth_authorize_vnode(cred, action, vp, NULL,
    282  1.13  christos 	    genfs_can_chflags(vp, cred, ip->uid, changing_sysflags));
    283   1.3      elad 	if (error)
    284   1.1     ahoka 		return error;
    285   1.1     ahoka 
    286   1.3      elad 	if (changing_sysflags) {
    287   1.1     ahoka 		ip->flags = flags;
    288   1.1     ahoka 	} else {
    289   1.1     ahoka 		ip->flags &= SF_SETTABLE;
    290   1.1     ahoka 		ip->flags |= (flags & UF_SETTABLE);
    291   1.1     ahoka 	}
    292   1.1     ahoka 	ip->iflag |= IN_CHANGE;
    293   1.1     ahoka 	error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
    294   1.1     ahoka 	if (error)
    295   1.1     ahoka 		return error;
    296   1.1     ahoka 
    297   1.1     ahoka 	if (flags & (IMMUTABLE | APPEND))
    298   1.1     ahoka 		return 0;
    299   1.1     ahoka 
    300   1.1     ahoka 	return error;
    301   1.1     ahoka }
    302   1.1     ahoka 
    303   1.1     ahoka 
    304   1.8     ttoth /* chfs_itimes - updates a vnode times to the given data */
    305   1.1     ahoka void
    306   1.1     ahoka chfs_itimes(struct chfs_inode *ip, const struct timespec *acc,
    307   1.1     ahoka     const struct timespec *mod, const struct timespec *cre)
    308   1.1     ahoka {
    309   1.1     ahoka 	struct timespec now;
    310   1.1     ahoka 
    311   1.1     ahoka 	if (!(ip->iflag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY))) {
    312   1.1     ahoka 		return;
    313   1.1     ahoka 	}
    314   1.1     ahoka 
    315   1.1     ahoka 	vfs_timestamp(&now);
    316   1.1     ahoka 	if (ip->iflag & IN_ACCESS) {
    317   1.1     ahoka 		if (acc == NULL)
    318   1.1     ahoka 			acc = &now;
    319   1.1     ahoka 		ip->atime = acc->tv_sec;
    320   1.1     ahoka 	}
    321   1.1     ahoka 	if (ip->iflag & (IN_UPDATE | IN_MODIFY)) {
    322   1.1     ahoka 		if (mod == NULL)
    323   1.1     ahoka 			mod = &now;
    324   1.1     ahoka 		ip->mtime = mod->tv_sec;
    325   1.1     ahoka 	}
    326   1.1     ahoka 	if (ip->iflag & (IN_CHANGE | IN_MODIFY)) {
    327   1.1     ahoka 		if (cre == NULL)
    328   1.1     ahoka 			cre = &now;
    329   1.1     ahoka 		ip->ctime = cre->tv_sec;
    330   1.1     ahoka 	}
    331   1.1     ahoka 	if (ip->iflag & (IN_ACCESS | IN_MODIFY))
    332   1.1     ahoka 		ip->iflag |= IN_ACCESSED;
    333   1.1     ahoka 	if (ip->iflag & (IN_UPDATE | IN_CHANGE))
    334   1.1     ahoka 		ip->iflag |= IN_MODIFIED;
    335   1.1     ahoka 	ip->iflag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY);
    336   1.1     ahoka }
    337   1.1     ahoka 
    338   1.8     ttoth /* chfs_update - updates a vnode times */
    339   1.1     ahoka int
    340   1.1     ahoka chfs_update(struct vnode *vp, const struct timespec *acc,
    341   1.1     ahoka     const struct timespec *mod, int flags)
    342   1.1     ahoka {
    343   1.1     ahoka 	struct chfs_inode *ip;
    344   1.1     ahoka 
    345   1.1     ahoka 	/* XXX ufs_reclaim calls this function unlocked! */
    346   1.1     ahoka 
    347   1.1     ahoka 	ip = VTOI(vp);
    348   1.1     ahoka 	chfs_itimes(ip, acc, mod, NULL);
    349   1.1     ahoka 
    350   1.1     ahoka 	return (0);
    351   1.1     ahoka }
    352   1.1     ahoka 
    353