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