1 /* $NetBSD: chfs_subr.c,v 1.9 2013/10/20 17:18:38 christos Exp $ */
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
7 * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/dirent.h>
39 #include <sys/event.h>
41 #include <sys/mount.h>
42 #include <sys/namei.h>
45 #include <sys/systm.h>
47 #include <sys/vnode.h>
48 #include <sys/kauth.h>
50 #include <sys/atomic.h>
54 #include <miscfs/specfs/specdev.h>
55 #include <miscfs/genfs/genfs.h>
61 * Returns information about the number of available memory pages,
62 * including physical and virtual ones.
64 * If 'total' is true, the value returned is the total amount of memory
65 * pages configured for the system (either in use or free).
66 * If it is FALSE, the value returned is the amount of free memory pages.
68 * Remember to remove DUMMYFS_PAGES_RESERVED from the returned value to avoid
69 * excessive memory usage.
73 chfs_mem_info(bool total
)
78 size
+= uvmexp
.swpgavail
;
80 size
-= uvmexp
.swpgonly
;
83 size
+= uvmexp
.filepages
;
84 if (size
> uvmexp
.wired
) {
96 * Looks for a directory entry in the directory represented by node.
97 * 'cnp' describes the name of the entry to look for. Note that the .
98 * and .. components are not allowed as they do not physically exist
101 * Returns a pointer to the entry when found, otherwise NULL.
104 chfs_dir_lookup(struct chfs_inode
*ip
, struct componentname
*cnp
)
107 struct chfs_dirent
*fd
;
108 dbg("dir_lookup()\n");
110 KASSERT(IMPLIES(cnp
->cn_namelen
== 1, cnp
->cn_nameptr
[0] != '.'));
111 KASSERT(IMPLIES(cnp
->cn_namelen
== 2, !(cnp
->cn_nameptr
[0] == '.' &&
112 cnp
->cn_nameptr
[1] == '.')));
115 TAILQ_FOREACH(fd
, &ip
->dents
, fds
) {
116 KASSERT(cnp
->cn_namelen
< 0xffff);
119 if (fd
->nsize
== (uint16_t)cnp
->cn_namelen
&&
120 memcmp(fd
->name
, cnp
->cn_nameptr
, fd
->nsize
) == 0) {
126 return found
? fd
: NULL
;
131 * Creates a (kernel) dirent and moves it to the given memory address.
132 * Used during readdir.
135 chfs_filldir(struct uio
* uio
, ino_t ino
, const char *name
,
136 int namelen
, enum chtype type
)
141 memset(&dent
, 0, sizeof(dent
));
146 dent
.d_type
= DT_BLK
;
150 dent
.d_type
= DT_CHR
;
154 dent
.d_type
= DT_DIR
;
158 dent
.d_type
= DT_FIFO
;
162 dent
.d_type
= DT_LNK
;
166 dent
.d_type
= DT_REG
;
170 dent
.d_type
= DT_SOCK
;
176 dent
.d_namlen
= namelen
;
177 (void)memcpy(dent
.d_name
, name
, dent
.d_namlen
);
178 dent
.d_reclen
= _DIRENT_SIZE(&dent
);
180 if (dent
.d_reclen
> uio
->uio_resid
) {
183 error
= uiomove(&dent
, dent
.d_reclen
, uio
);
190 * chfs_chsize - change size of the given vnode
191 * Caller should execute chfs_update on vp after a successful execution.
192 * The vnode must be locked on entry and remain locked on exit.
195 chfs_chsize(struct vnode
*vp
, u_quad_t size
, kauth_cred_t cred
)
197 struct chfs_mount
*chmp
;
198 struct chfs_inode
*ip
;
203 dbg("chfs_chsize\n");
205 switch (ip
->ch_type
) {
210 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
218 return EOPNOTSUPP
; /* XXX why not ENODEV? */
223 mutex_enter(&chmp
->chm_lock_mountfields
);
225 if (ip
->size
< size
) {
226 uvm_vnp_setsize(vp
, size
);
227 chfs_set_vnode_size(vp
, size
);
228 ip
->iflag
|= IN_CHANGE
| IN_UPDATE
;
230 mutex_exit(&chmp
->chm_lock_mountfields
);
235 ubc_zerorange(&vp
->v_uobj
, size
, ip
->size
- size
, UBC_UNMAP_FLAG(vp
));
238 /* drop unused fragments */
239 chfs_truncate_fragtree(ip
->chmp
, &ip
->fragtree
, size
);
241 uvm_vnp_setsize(vp
, size
);
242 chfs_set_vnode_size(vp
, size
);
243 ip
->iflag
|= IN_CHANGE
| IN_UPDATE
;
244 mutex_exit(&chmp
->chm_lock_mountfields
);
249 * chfs_chflags - change flags of the given vnode
250 * Caller should execute chfs_update on vp after a successful execution.
251 * The vnode must be locked on entry and remain locked on exit.
254 chfs_chflags(struct vnode
*vp
, int flags
, kauth_cred_t cred
)
256 struct chfs_inode
*ip
;
258 kauth_action_t action
= KAUTH_VNODE_WRITE_FLAGS
;
259 bool changing_sysflags
= false;
263 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
266 if ((flags
& SF_SNAPSHOT
) != (ip
->flags
& SF_SNAPSHOT
))
269 /* Indicate we're changing system flags if we are. */
270 if ((ip
->flags
& SF_SETTABLE
) != (flags
& SF_SETTABLE
) ||
271 (flags
& UF_SETTABLE
) != flags
) {
272 action
|= KAUTH_VNODE_WRITE_SYSFLAGS
;
273 changing_sysflags
= true;
276 /* Indicate the node has system flags if it does. */
277 if (ip
->flags
& (SF_IMMUTABLE
| SF_APPEND
)) {
278 action
|= KAUTH_VNODE_HAS_SYSFLAGS
;
281 error
= kauth_authorize_vnode(cred
, action
, vp
, NULL
,
282 genfs_can_chflags(cred
, CHTTOVT(ip
->ch_type
), ip
->uid
, changing_sysflags
));
286 if (changing_sysflags
) {
289 ip
->flags
&= SF_SETTABLE
;
290 ip
->flags
|= (flags
& UF_SETTABLE
);
292 ip
->iflag
|= IN_CHANGE
;
293 error
= chfs_update(vp
, NULL
, NULL
, UPDATE_WAIT
);
297 if (flags
& (IMMUTABLE
| APPEND
))
304 /* chfs_itimes - updates a vnode times to the given data */
306 chfs_itimes(struct chfs_inode
*ip
, const struct timespec
*acc
,
307 const struct timespec
*mod
, const struct timespec
*cre
)
311 if (!(ip
->iflag
& (IN_ACCESS
| IN_CHANGE
| IN_UPDATE
| IN_MODIFY
))) {
316 if (ip
->iflag
& IN_ACCESS
) {
319 ip
->atime
= acc
->tv_sec
;
321 if (ip
->iflag
& (IN_UPDATE
| IN_MODIFY
)) {
324 ip
->mtime
= mod
->tv_sec
;
326 if (ip
->iflag
& (IN_CHANGE
| IN_MODIFY
)) {
329 ip
->ctime
= cre
->tv_sec
;
331 if (ip
->iflag
& (IN_ACCESS
| IN_MODIFY
))
332 ip
->iflag
|= IN_ACCESSED
;
333 if (ip
->iflag
& (IN_UPDATE
| IN_CHANGE
))
334 ip
->iflag
|= IN_MODIFIED
;
335 ip
->iflag
&= ~(IN_ACCESS
| IN_CHANGE
| IN_UPDATE
| IN_MODIFY
);
338 /* chfs_update - updates a vnode times */
340 chfs_update(struct vnode
*vp
, const struct timespec
*acc
,
341 const struct timespec
*mod
, int flags
)
343 struct chfs_inode
*ip
;
345 /* XXX ufs_reclaim calls this function unlocked! */
348 chfs_itimes(ip
, acc
, mod
, NULL
);