tmpfs.h revision 1.41 1 1.41 rmind /* $NetBSD: tmpfs.h,v 1.41 2011/05/24 20:17:49 rmind Exp $ */
2 1.1 jmmv
3 1.1 jmmv /*
4 1.30 ad * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
5 1.1 jmmv * All rights reserved.
6 1.1 jmmv *
7 1.1 jmmv * This code is derived from software contributed to The NetBSD Foundation
8 1.6 jmmv * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 1.6 jmmv * 2005 program.
10 1.1 jmmv *
11 1.1 jmmv * Redistribution and use in source and binary forms, with or without
12 1.1 jmmv * modification, are permitted provided that the following conditions
13 1.1 jmmv * are met:
14 1.1 jmmv * 1. Redistributions of source code must retain the above copyright
15 1.1 jmmv * notice, this list of conditions and the following disclaimer.
16 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 jmmv * notice, this list of conditions and the following disclaimer in the
18 1.1 jmmv * documentation and/or other materials provided with the distribution.
19 1.1 jmmv *
20 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.1 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.1 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1 jmmv * POSSIBILITY OF SUCH DAMAGE.
31 1.1 jmmv */
32 1.1 jmmv
33 1.10 christos #ifndef _FS_TMPFS_TMPFS_H_
34 1.10 christos #define _FS_TMPFS_TMPFS_H_
35 1.1 jmmv
36 1.1 jmmv #include <sys/dirent.h>
37 1.1 jmmv #include <sys/mount.h>
38 1.38 rmind #include <sys/pool.h>
39 1.1 jmmv #include <sys/queue.h>
40 1.1 jmmv #include <sys/vnode.h>
41 1.1 jmmv
42 1.37 pooka /*
43 1.37 pooka * Internal representation of a tmpfs directory entry.
44 1.41 rmind *
45 1.41 rmind * All fields are protected by vnode lock.
46 1.37 pooka */
47 1.41 rmind typedef struct tmpfs_dirent {
48 1.37 pooka TAILQ_ENTRY(tmpfs_dirent) td_entries;
49 1.37 pooka
50 1.41 rmind /* Pointer to the inode this entry refers to. */
51 1.41 rmind struct tmpfs_node * td_node;
52 1.37 pooka
53 1.41 rmind /* Name and its length. */
54 1.37 pooka char * td_name;
55 1.41 rmind uint16_t td_namelen;
56 1.41 rmind } tmpfs_dirent_t;
57 1.37 pooka
58 1.37 pooka TAILQ_HEAD(tmpfs_dir, tmpfs_dirent);
59 1.37 pooka
60 1.37 pooka #if defined(_KERNEL)
61 1.41 rmind
62 1.41 rmind /* Validate maximum td_namelen length. */
63 1.41 rmind CTASSERT(MAXNAMLEN < UINT16_MAX);
64 1.41 rmind
65 1.4 yamt #define TMPFS_DIRCOOKIE_DOT 0
66 1.4 yamt #define TMPFS_DIRCOOKIE_DOTDOT 1
67 1.4 yamt #define TMPFS_DIRCOOKIE_EOF 2
68 1.41 rmind
69 1.41 rmind /*
70 1.41 rmind * Each entry in a directory has a cookie that identifies it. Cookies
71 1.41 rmind * supersede offsets within directories, as tmpfs has no offsets as such.
72 1.41 rmind *
73 1.41 rmind * The '.', '..' and the end of directory markers have fixed cookies,
74 1.41 rmind * which cannot collide with the cookies generated by other entries.
75 1.41 rmind *
76 1.41 rmind * The cookies for the other entries are generated based on the memory
77 1.41 rmind * address of their representative meta-data structure.
78 1.41 rmind *
79 1.41 rmind * XXX: Truncating directory cookies to 31 bits now - workaround for
80 1.41 rmind * problem with Linux compat, see PR/32034.
81 1.41 rmind */
82 1.41 rmind static inline off_t
83 1.41 rmind tmpfs_dircookie(tmpfs_dirent_t *de)
84 1.22 jmmv {
85 1.22 jmmv off_t cookie;
86 1.22 jmmv
87 1.22 jmmv cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF;
88 1.22 jmmv KASSERT(cookie != TMPFS_DIRCOOKIE_DOT);
89 1.22 jmmv KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT);
90 1.22 jmmv KASSERT(cookie != TMPFS_DIRCOOKIE_EOF);
91 1.22 jmmv
92 1.22 jmmv return cookie;
93 1.22 jmmv }
94 1.41 rmind #endif
95 1.1 jmmv
96 1.37 pooka /*
97 1.41 rmind * Internal representation of a tmpfs file system node -- inode.
98 1.37 pooka *
99 1.37 pooka * This structure is splitted in two parts: one holds attributes common
100 1.37 pooka * to all file types and the other holds data that is only applicable to
101 1.41 rmind * a particular type.
102 1.41 rmind *
103 1.41 rmind * All fields are protected by vnode lock. The vnode association itself
104 1.41 rmind * is protected by tmpfs_node_t::tn_vlock.
105 1.37 pooka */
106 1.41 rmind typedef struct tmpfs_node {
107 1.37 pooka LIST_ENTRY(tmpfs_node) tn_entries;
108 1.37 pooka
109 1.41 rmind /* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */
110 1.37 pooka enum vtype tn_type;
111 1.37 pooka
112 1.41 rmind /* Inode identifier. */
113 1.37 pooka ino_t tn_id;
114 1.37 pooka
115 1.41 rmind /* Inode status flags (for operations in delayed manner). */
116 1.37 pooka int tn_status;
117 1.37 pooka
118 1.41 rmind /* The inode size. */
119 1.37 pooka off_t tn_size;
120 1.37 pooka
121 1.37 pooka /* Generic node attributes. */
122 1.37 pooka uid_t tn_uid;
123 1.37 pooka gid_t tn_gid;
124 1.37 pooka mode_t tn_mode;
125 1.37 pooka int tn_flags;
126 1.37 pooka nlink_t tn_links;
127 1.37 pooka struct timespec tn_atime;
128 1.37 pooka struct timespec tn_mtime;
129 1.37 pooka struct timespec tn_ctime;
130 1.37 pooka struct timespec tn_birthtime;
131 1.37 pooka unsigned long tn_gen;
132 1.37 pooka
133 1.37 pooka /* Head of byte-level lock list (used by tmpfs_advlock). */
134 1.37 pooka struct lockf * tn_lockf;
135 1.37 pooka
136 1.41 rmind /*
137 1.41 rmind * Each inode has a corresponding vnode. It is a bi-directional
138 1.41 rmind * association. Whenever vnode is allocated, its v_data field is
139 1.41 rmind * set to the inode it reference, and tmpfs_node_t::tn_vnode is
140 1.41 rmind * set to point to the said vnode.
141 1.37 pooka *
142 1.41 rmind * Further attempts to allocate a vnode for this same node will
143 1.37 pooka * result in returning a new reference to the value stored in
144 1.41 rmind * tn_vnode. It may be NULL when the node is unused (that is,
145 1.41 rmind * no vnode has been allocated or it has been reclaimed).
146 1.41 rmind */
147 1.37 pooka kmutex_t tn_vlock;
148 1.41 rmind vnode_t * tn_vnode;
149 1.37 pooka
150 1.37 pooka union {
151 1.41 rmind /* Type case: VBLK or VCHR. */
152 1.37 pooka struct {
153 1.37 pooka dev_t tn_rdev;
154 1.37 pooka } tn_dev;
155 1.37 pooka
156 1.41 rmind /* Type case: VDIR. */
157 1.37 pooka struct {
158 1.41 rmind /* Parent directory (root inode points to itself). */
159 1.37 pooka struct tmpfs_node * tn_parent;
160 1.37 pooka
161 1.41 rmind /* List of directory entries. */
162 1.37 pooka struct tmpfs_dir tn_dir;
163 1.37 pooka
164 1.41 rmind /*
165 1.41 rmind * Number and pointer of the last directory entry
166 1.41 rmind * returned by the readdir(3) operation.
167 1.41 rmind */
168 1.37 pooka off_t tn_readdir_lastn;
169 1.37 pooka struct tmpfs_dirent * tn_readdir_lastp;
170 1.37 pooka } tn_dir;
171 1.37 pooka
172 1.41 rmind /* Type case: VLNK. */
173 1.37 pooka struct tn_lnk {
174 1.41 rmind /* The link's target. */
175 1.37 pooka char * tn_link;
176 1.37 pooka } tn_lnk;
177 1.37 pooka
178 1.41 rmind /* Type case: VREG. */
179 1.37 pooka struct tn_reg {
180 1.41 rmind /* Underlying UVM object to store contents. */
181 1.37 pooka struct uvm_object * tn_aobj;
182 1.37 pooka size_t tn_aobj_pages;
183 1.37 pooka } tn_reg;
184 1.37 pooka } tn_spec;
185 1.41 rmind } tmpfs_node_t;
186 1.37 pooka
187 1.37 pooka #if defined(_KERNEL)
188 1.41 rmind
189 1.1 jmmv LIST_HEAD(tmpfs_node_list, tmpfs_node);
190 1.1 jmmv
191 1.41 rmind /* Status flags. */
192 1.41 rmind #define TMPFS_NODE_ACCESSED 0x01
193 1.41 rmind #define TMPFS_NODE_MODIFIED 0x02
194 1.41 rmind #define TMPFS_NODE_CHANGED 0x04
195 1.41 rmind
196 1.41 rmind #define TMPFS_NODE_STATUSALL \
197 1.41 rmind (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED)
198 1.41 rmind
199 1.41 rmind /* White-out inode indicator. */
200 1.41 rmind #define TMPFS_NODE_WHITEOUT ((struct tmpfs_node *)-1)
201 1.1 jmmv
202 1.1 jmmv /*
203 1.6 jmmv * Internal representation of a tmpfs mount point.
204 1.1 jmmv */
205 1.41 rmind typedef struct tmpfs_mount {
206 1.38 rmind /* Limit and number of bytes in use by the file system. */
207 1.38 rmind uint64_t tm_mem_limit;
208 1.38 rmind uint64_t tm_bytes_used;
209 1.38 rmind kmutex_t tm_acc_lock;
210 1.1 jmmv
211 1.41 rmind /* Pointer to the root inode. */
212 1.41 rmind tmpfs_node_t * tm_root;
213 1.41 rmind
214 1.41 rmind /* Maximum number of possible nodes for this file system. */
215 1.32 jmmv unsigned int tm_nodes_max;
216 1.6 jmmv
217 1.41 rmind /* Number of nodes currently allocated. */
218 1.32 jmmv unsigned int tm_nodes_cnt;
219 1.6 jmmv
220 1.41 rmind /* List of inodes and the lock protecting it. */
221 1.30 ad kmutex_t tm_lock;
222 1.30 ad struct tmpfs_node_list tm_nodes;
223 1.41 rmind } tmpfs_mount_t;
224 1.1 jmmv
225 1.1 jmmv /*
226 1.1 jmmv * This structure maps a file identifier to a tmpfs node. Used by the
227 1.1 jmmv * NFS code.
228 1.1 jmmv */
229 1.41 rmind typedef struct tmpfs_fid {
230 1.1 jmmv uint16_t tf_len;
231 1.1 jmmv uint16_t tf_pad;
232 1.18 riz uint32_t tf_gen;
233 1.1 jmmv ino_t tf_id;
234 1.41 rmind } tmpfs_fid_t;
235 1.1 jmmv
236 1.1 jmmv /*
237 1.1 jmmv * Prototypes for tmpfs_subr.c.
238 1.1 jmmv */
239 1.1 jmmv
240 1.1 jmmv int tmpfs_alloc_node(struct tmpfs_mount *, enum vtype,
241 1.1 jmmv uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *,
242 1.29 pooka char *, dev_t, struct tmpfs_node **);
243 1.1 jmmv void tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);
244 1.1 jmmv int tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *,
245 1.1 jmmv const char *, uint16_t, struct tmpfs_dirent **);
246 1.1 jmmv void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *,
247 1.25 thorpej bool);
248 1.1 jmmv int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **);
249 1.1 jmmv void tmpfs_free_vp(struct vnode *);
250 1.1 jmmv int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
251 1.1 jmmv struct componentname *, char *);
252 1.1 jmmv void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
253 1.1 jmmv void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
254 1.1 jmmv struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node,
255 1.1 jmmv struct componentname *cnp);
256 1.1 jmmv int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
257 1.1 jmmv int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
258 1.4 yamt struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
259 1.4 yamt int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
260 1.1 jmmv int tmpfs_reg_resize(struct vnode *, off_t);
261 1.21 ad int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *);
262 1.21 ad int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
263 1.21 ad int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *);
264 1.21 ad int tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct lwp *);
265 1.34 christos int tmpfs_chtimes(struct vnode *, const struct timespec *,
266 1.34 christos const struct timespec *, const struct timespec *, int, kauth_cred_t,
267 1.34 christos struct lwp *);
268 1.9 yamt void tmpfs_update(struct vnode *, const struct timespec *,
269 1.34 christos const struct timespec *, const struct timespec *, int);
270 1.9 yamt int tmpfs_truncate(struct vnode *, off_t);
271 1.9 yamt
272 1.38 rmind /*
273 1.38 rmind * Prototypes for tmpfs_mem.c.
274 1.38 rmind */
275 1.38 rmind
276 1.38 rmind void tmpfs_mntmem_init(struct tmpfs_mount *, uint64_t);
277 1.38 rmind void tmpfs_mntmem_destroy(struct tmpfs_mount *);
278 1.38 rmind
279 1.38 rmind size_t tmpfs_mem_info(bool);
280 1.38 rmind uint64_t tmpfs_bytes_max(struct tmpfs_mount *);
281 1.38 rmind size_t tmpfs_pages_avail(struct tmpfs_mount *);
282 1.38 rmind bool tmpfs_mem_incr(struct tmpfs_mount *, size_t);
283 1.38 rmind void tmpfs_mem_decr(struct tmpfs_mount *, size_t);
284 1.38 rmind
285 1.38 rmind struct tmpfs_dirent *tmpfs_dirent_get(struct tmpfs_mount *);
286 1.38 rmind void tmpfs_dirent_put(struct tmpfs_mount *, struct tmpfs_dirent *);
287 1.38 rmind
288 1.38 rmind struct tmpfs_node *tmpfs_node_get(struct tmpfs_mount *);
289 1.38 rmind void tmpfs_node_put(struct tmpfs_mount *, struct tmpfs_node *);
290 1.38 rmind
291 1.38 rmind char * tmpfs_strname_alloc(struct tmpfs_mount *, size_t);
292 1.38 rmind void tmpfs_strname_free(struct tmpfs_mount *, char *, size_t);
293 1.38 rmind bool tmpfs_strname_neqlen(struct componentname *, struct componentname *);
294 1.38 rmind
295 1.1 jmmv /*
296 1.1 jmmv * Ensures that the node pointed by 'node' is a directory and that its
297 1.1 jmmv * contents are consistent with respect to directories.
298 1.1 jmmv */
299 1.1 jmmv #define TMPFS_VALIDATE_DIR(node) \
300 1.1 jmmv KASSERT((node)->tn_type == VDIR); \
301 1.4 yamt KASSERT((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \
302 1.15 jmmv KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \
303 1.22 jmmv tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \
304 1.15 jmmv (node)->tn_spec.tn_dir.tn_readdir_lastn);
305 1.1 jmmv
306 1.1 jmmv /*
307 1.1 jmmv * Memory management stuff.
308 1.1 jmmv */
309 1.1 jmmv
310 1.41 rmind /* Amount of memory pages to reserve for the system. */
311 1.41 rmind #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
312 1.1 jmmv
313 1.1 jmmv /*
314 1.41 rmind * Routines to convert VFS structures to tmpfs internal ones.
315 1.1 jmmv */
316 1.1 jmmv
317 1.41 rmind static inline tmpfs_mount_t *
318 1.1 jmmv VFS_TO_TMPFS(struct mount *mp)
319 1.1 jmmv {
320 1.41 rmind tmpfs_mount_t *tmp = mp->mnt_data;
321 1.1 jmmv
322 1.41 rmind KASSERT(tmp != NULL);
323 1.1 jmmv return tmp;
324 1.1 jmmv }
325 1.1 jmmv
326 1.41 rmind static inline tmpfs_node_t *
327 1.41 rmind VP_TO_TMPFS_DIR(vnode_t *vp)
328 1.37 pooka {
329 1.41 rmind tmpfs_node_t *node = vp->v_data;
330 1.37 pooka
331 1.41 rmind KASSERT(node != NULL);
332 1.41 rmind TMPFS_VALIDATE_DIR(node);
333 1.37 pooka return node;
334 1.37 pooka }
335 1.37 pooka
336 1.41 rmind #endif /* defined(_KERNEL) */
337 1.37 pooka
338 1.41 rmind static __inline tmpfs_node_t *
339 1.41 rmind VP_TO_TMPFS_NODE(struct vnode *vp)
340 1.1 jmmv {
341 1.41 rmind tmpfs_node_t *node = vp->v_data;
342 1.14 christos #ifdef KASSERT
343 1.41 rmind KASSERT(node != NULL);
344 1.14 christos #endif
345 1.1 jmmv return node;
346 1.1 jmmv }
347 1.37 pooka
348 1.10 christos #endif /* _FS_TMPFS_TMPFS_H_ */
349