]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/tmpfs/tmpfs.h
MFp4: Add tmpfs, an efficient memory file system.
[FreeBSD/FreeBSD.git] / sys / fs / tmpfs / tmpfs.h
1 /*      $NetBSD: tmpfs.h,v 1.14 2006/02/10 16:00:02 christos Exp $      */
2
3 /*
4  * Copyright (c) 2005 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  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  *
39  * $FreeBSD$
40  */
41
42 #ifndef _FS_TMPFS_TMPFS_H_
43 #define _FS_TMPFS_TMPFS_H_
44
45 /* ---------------------------------------------------------------------
46  * KERNEL-SPECIFIC DEFINITIONS
47  * --------------------------------------------------------------------- */
48 #include <sys/dirent.h>
49 #include <sys/mount.h>
50 #include <sys/queue.h>
51 #include <sys/vnode.h>
52 #include <sys/file.h>
53 #include <sys/lock.h>
54 #include <sys/mutex.h>
55
56 /* --------------------------------------------------------------------- */
57 #include <sys/malloc.h>
58 #include <sys/systm.h>
59 #include <sys/vmmeter.h>
60 #include <vm/swap_pager.h>
61
62 MALLOC_DECLARE(M_TMPFSMNT);
63
64 #include <fs/tmpfs/tmpfs_uma.h>
65
66 /* --------------------------------------------------------------------- */
67
68 /*
69  * Internal representation of a tmpfs directory entry.
70  */
71 struct tmpfs_dirent {
72         TAILQ_ENTRY(tmpfs_dirent)       td_entries;
73
74         /* Length of the name stored in this directory entry.  This avoids
75          * the need to recalculate it every time the name is used. */
76         uint16_t                        td_namelen;
77
78         /* The name of the entry, allocated from a string pool.  This
79         * string is not required to be zero-terminated; therefore, the
80         * td_namelen field must always be used when accessing its value. */
81         char *                          td_name;
82
83         /* Pointer to the node this entry refers to. */
84         struct tmpfs_node *             td_node;
85 };
86
87 /* A directory in tmpfs holds a sorted list of directory entries, which in
88  * turn point to other files (which can be directories themselves).
89  *
90  * In tmpfs, this list is managed by a tail queue, whose head is defined by
91  * the struct tmpfs_dir type.
92  *
93  * It is imporant to notice that directories do not have entries for . and
94  * .. as other file systems do.  These can be generated when requested
95  * based on information available by other means, such as the pointer to
96  * the node itself in the former case or the pointer to the parent directory
97  * in the latter case.  This is done to simplify tmpfs's code and, more
98  * importantly, to remove redundancy. */
99 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent);
100
101 #define TMPFS_DIRCOOKIE(dirent) ((off_t)(uintptr_t)(dirent))
102 #define TMPFS_DIRCOOKIE_DOT     0
103 #define TMPFS_DIRCOOKIE_DOTDOT  1
104 #define TMPFS_DIRCOOKIE_EOF     2
105
106 /* --------------------------------------------------------------------- */
107
108 /*
109  * Internal representation of a tmpfs file system node.
110  *
111  * This structure is splitted in two parts: one holds attributes common
112  * to all file types and the other holds data that is only applicable to
113  * a particular type.  The code must be careful to only access those
114  * attributes that are actually allowed by the node's type.
115  *
116  *
117  * Below is the key of locks used to protected the fields in the following
118  * structures.
119  *
120  */
121 struct tmpfs_node {
122         /* Doubly-linked list entry which links all existing nodes for a
123          * single file system.  This is provided to ease the removal of
124          * all nodes during the unmount operation. */
125         LIST_ENTRY(tmpfs_node)  tn_entries;
126
127         /* The node's type.  Any of 'VBLK', 'VCHR', 'VDIR', 'VFIFO',
128          * 'VLNK', 'VREG' and 'VSOCK' is allowed.  The usage of vnode
129          * types instead of a custom enumeration is to make things simpler
130          * and faster, as we do not need to convert between two types. */
131         enum vtype              tn_type;
132
133         /* Node identifier. */
134         ino_t                   tn_id;
135
136         /* Node's internal status.  This is used by several file system
137          * operations to do modifications to the node in a delayed
138          * fashion. */
139         int                     tn_status;
140 #define TMPFS_NODE_ACCESSED     (1 << 1)
141 #define TMPFS_NODE_MODIFIED     (1 << 2)
142 #define TMPFS_NODE_CHANGED      (1 << 3)
143
144         /* The node size.  It does not necessarily match the real amount
145          * of memory consumed by it. */
146         off_t                   tn_size;
147
148         /* Generic node attributes. */
149         uid_t                   tn_uid;
150         gid_t                   tn_gid;
151         mode_t                  tn_mode;
152         int                     tn_flags;
153         nlink_t                 tn_links;
154         struct timespec         tn_atime;
155         struct timespec         tn_mtime;
156         struct timespec         tn_ctime;
157         struct timespec         tn_birthtime;
158         unsigned long           tn_gen;
159
160         /* Head of byte-level lock list (used by tmpfs_advlock). */
161         struct lockf *          tn_lockf;
162
163         /* As there is a single vnode for each active file within the
164          * system, care has to be taken to avoid allocating more than one
165          * vnode per file.  In order to do this, a bidirectional association
166          * is kept between vnodes and nodes.
167          *
168          * Whenever a vnode is allocated, its v_data field is updated to
169          * point to the node it references.  At the same time, the node's
170          * tn_vnode field is modified to point to the new vnode representing
171          * it.  Further attempts to allocate a vnode for this same node will
172          * result in returning a new reference to the value stored in
173          * tn_vnode.
174          *
175          * May be NULL when the node is unused (that is, no vnode has been
176          * allocated for it or it has been reclaimed). */
177         struct vnode *          tn_vnode;
178
179         /* Pointer to the node returned by tmpfs_lookup() after doing a
180          * delete or a rename lookup; its value is only valid in these two
181          * situations.  In case we were looking up . or .., it holds a null
182          * pointer. */
183         struct tmpfs_dirent *   tn_lookup_dirent;
184
185         /* interlock to protect tn_vpstate */
186         struct mtx      tn_interlock;
187
188         /* Identify if current node has vnode assiocate with
189          * or allocating vnode.
190          */
191         int             tn_vpstate;
192
193         /* misc data field for different tn_type node */
194         union {
195                 /* Valid when tn_type == VBLK || tn_type == VCHR. */
196                 dev_t                   tn_rdev;
197
198                 /* Valid when tn_type == VDIR. */
199                 struct tn_dir{
200                         /* Pointer to the parent directory.  The root
201                          * directory has a pointer to itself in this field;
202                          * this property identifies the root node. */
203                         struct tmpfs_node *     tn_parent;
204
205                         /* Head of a tail-queue that links the contents of
206                          * the directory together.  See above for a
207                          * description of its contents. */
208                         struct tmpfs_dir        tn_dirhead;
209
210                         /* Number and pointer of the first directory entry
211                          * returned by the readdir operation if it were
212                          * called again to continue reading data from the
213                          * same directory as before.  This is used to speed
214                          * up reads of long directories, assuming that no
215                          * more than one read is in progress at a given time.
216                          * Otherwise, these values are discarded and a linear
217                          * scan is performed from the beginning up to the
218                          * point where readdir starts returning values. */
219                         off_t                   tn_readdir_lastn;
220                         struct tmpfs_dirent *   tn_readdir_lastp;
221                 }tn_dir;
222
223                 /* Valid when tn_type == VLNK. */
224                 /* The link's target, allocated from a string pool. */
225                 char *                  tn_link;
226
227                 /* Valid when tn_type == VREG. */
228                 struct tn_reg {
229                         /* The contents of regular files stored in a tmpfs
230                          * file system are represented by a single anonymous
231                          * memory object (aobj, for short).  The aobj provides
232                          * direct access to any position within the file,
233                          * because its contents are always mapped in a
234                          * contiguous region of virtual memory.  It is a task
235                          * of the memory management subsystem (see uvm(9)) to
236                          * issue the required page ins or page outs whenever
237                          * a position within the file is accessed. */
238                         vm_object_t             tn_aobj;
239                         size_t                  tn_aobj_pages;
240
241                 }tn_reg;
242
243                 /* Valid when tn_type = VFIFO */
244                 struct tn_fifo {
245                         fo_rdwr_t               *tn_fo_read;
246                         fo_rdwr_t               *tn_fo_write;
247                 }tn_fifo;
248         }tn_spec;
249 };
250 LIST_HEAD(tmpfs_node_list, tmpfs_node);
251
252 #define tn_rdev tn_spec.tn_rdev
253 #define tn_dir tn_spec.tn_dir
254 #define tn_link tn_spec.tn_link
255 #define tn_reg tn_spec.tn_reg
256 #define tn_fifo tn_spec.tn_fifo
257
258 #define TMPFS_NODE_LOCK(node) mtx_lock(&(node)->tn_interlock)
259 #define TMPFS_NODE_UNLOCK(node) mtx_unlock(&(node)->tn_interlock)
260
261 #define TMPFS_VNODE_ALLOCATING  1
262 #define TMPFS_VNODE_WANT        2
263 /* --------------------------------------------------------------------- */
264
265 /*
266  * Internal representation of a tmpfs mount point.
267  */
268 struct tmpfs_mount {
269         /* Maximum number of memory pages available for use by the file
270          * system, set during mount time.  This variable must never be
271          * used directly as it may be bigger that the current amount of
272          * free memory; in the extreme case, it will hold the SIZE_MAX
273          * value.  Instead, use the TMPFS_PAGES_MAX macro. */
274         size_t                  tm_pages_max;
275
276         /* Number of pages in use by the file system.  Cannot be bigger
277          * than the value returned by TMPFS_PAGES_MAX in any case. */
278         size_t                  tm_pages_used;
279
280         /* Pointer to the node representing the root directory of this
281          * file system. */
282         struct tmpfs_node *     tm_root;
283
284         /* Maximum number of possible nodes for this file system; set
285          * during mount time.  We need a hard limit on the maximum number
286          * of nodes to avoid allocating too much of them; their objects
287          * cannot be released until the file system is unmounted.
288          * Otherwise, we could easily run out of memory by creating lots
289          * of empty files and then simply removing them. */
290         ino_t                   tm_nodes_max;
291
292         /* Number of nodes currently allocated.  This number only grows.
293          * When it reaches tm_nodes_max, no more new nodes can be allocated.
294          * Of course, the old, unused ones can be reused. */
295         ino_t                   tm_nodes_last;
296
297         /* Number of nodes currently that are in use. */
298         ino_t                   tm_nodes_inuse;
299
300         /* maximum representable file size */
301         u_int64_t               tm_maxfilesize;
302         
303         /* Nodes are organized in two different lists.  The used list
304          * contains all nodes that are currently used by the file system;
305          * i.e., they refer to existing files.  The available list contains
306          * all nodes that are currently available for use by new files.
307          * Nodes must be kept in this list (instead of deleting them)
308          * because we need to keep track of their generation number (tn_gen
309          * field).
310          *
311          * Note that nodes are lazily allocated: if the available list is
312          * empty and we have enough space to create more nodes, they will be
313          * created and inserted in the used list.  Once these are released,
314          * they will go into the available list, remaining alive until the
315          * file system is unmounted. */
316         struct tmpfs_node_list  tm_nodes_used;
317         struct tmpfs_node_list  tm_nodes_avail;
318
319         /* All node lock to protect the node list and tmp_pages_used */
320         struct mtx allnode_lock;
321
322         /* Pools used to store file system meta data.  These are not shared
323          * across several instances of tmpfs for the reasons described in
324          * tmpfs_pool.c. */
325         uma_zone_t              tm_dirent_pool;
326         uma_zone_t              tm_node_pool;
327         struct tmpfs_str_zone   tm_str_pool;
328 };
329 #define TMPFS_LOCK(tm) mtx_lock(&(tm)->allnode_lock)
330 #define TMPFS_UNLOCK(tm) mtx_unlock(&(tm)->allnode_lock)
331
332 /* --------------------------------------------------------------------- */
333
334 /*
335  * This structure maps a file identifier to a tmpfs node.  Used by the
336  * NFS code.
337  */
338 struct tmpfs_fid {
339         uint16_t                tf_len;
340         uint16_t                tf_pad;
341         unsigned long           tf_gen;
342         ino_t                   tf_id;
343 };
344
345 /* --------------------------------------------------------------------- */
346
347 #ifdef _KERNEL
348 /*
349  * Prototypes for tmpfs_subr.c.
350  */
351
352 int     tmpfs_alloc_node(struct tmpfs_mount *, enum vtype,
353             uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *,
354             char *, dev_t, struct thread *, struct tmpfs_node **);
355 void    tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);
356 int     tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *,
357             const char *, uint16_t, struct tmpfs_dirent **);
358 void    tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *,
359             boolean_t);
360 int     tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **,
361             struct thread *td);
362 void    tmpfs_free_vp(struct vnode *);
363 int     tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
364             struct componentname *, char *);
365 void    tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
366 void    tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
367 struct tmpfs_dirent *   tmpfs_dir_lookup(struct tmpfs_node *node,
368                             struct componentname *cnp);
369 int     tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
370 int     tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
371 struct tmpfs_dirent *   tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
372 int     tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
373 int     tmpfs_reg_resize(struct vnode *, off_t);
374 int     tmpfs_chflags(struct vnode *, int, struct ucred *, struct thread *);
375 int     tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct thread *);
376 int     tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *,
377             struct thread *);
378 int     tmpfs_chsize(struct vnode *, u_quad_t, struct ucred *, struct thread *);
379 int     tmpfs_chtimes(struct vnode *, struct timespec *, struct timespec *, 
380             struct timespec *, int, struct ucred *, struct thread *);
381 void    tmpfs_itimes(struct vnode *, const struct timespec *,
382             const struct timespec *);
383
384 void    tmpfs_update(struct vnode *);
385 int     tmpfs_truncate(struct vnode *, off_t);
386
387 /* --------------------------------------------------------------------- */
388
389 /*
390  * Convenience macros to simplify some logical expressions.
391  */
392 #define IMPLIES(a, b) (!(a) || (b))
393 #define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
394
395 /* --------------------------------------------------------------------- */
396
397 /*
398  * Checks that the directory entry pointed by 'de' matches the name 'name'
399  * with a length of 'len'.
400  */
401 #define TMPFS_DIRENT_MATCHES(de, name, len) \
402     (de->td_namelen == (uint16_t)len && \
403     memcmp((de)->td_name, (name), (de)->td_namelen) == 0)
404
405 /* --------------------------------------------------------------------- */
406
407 /*
408  * Ensures that the node pointed by 'node' is a directory and that its
409  * contents are consistent with respect to directories.
410  */
411 #define TMPFS_VALIDATE_DIR(node) \
412     MPASS((node)->tn_type == VDIR); \
413     MPASS((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \
414     MPASS((node)->tn_dir.tn_readdir_lastp == NULL || \
415         TMPFS_DIRCOOKIE((node)->tn_dir.tn_readdir_lastp) == (node)->tn_dir.tn_readdir_lastn);
416
417 /* --------------------------------------------------------------------- */
418
419 /*
420  * Memory management stuff.
421  */
422
423 /* Amount of memory pages to reserve for the system (e.g., to not use by
424  * tmpfs).
425  * XXX: Should this be tunable through sysctl, for instance? */
426 #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
427
428 /*
429  * Returns information about the number of available memory pages,
430  * including physical and virtual ones.
431  *
432  * If 'total' is TRUE, the value returned is the total amount of memory 
433  * pages configured for the system (either in use or free).
434  * If it is FALSE, the value returned is the amount of free memory pages.
435  *
436  * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
437  * excessive memory usage.
438  *
439  */
440 static __inline size_t
441 tmpfs_mem_info(void)
442 {
443         size_t size;
444
445         size = swap_pager_avail + cnt.v_free_count + cnt.v_inactive_count;
446         size -= size > cnt.v_wire_count ? cnt.v_wire_count : size;
447         return size;
448 }
449
450 /* Returns the maximum size allowed for a tmpfs file system.  This macro
451  * must be used instead of directly retrieving the value from tm_pages_max.
452  * The reason is that the size of a tmpfs file system is dynamic: it lets
453  * the user store files as long as there is enough free memory (including
454  * physical memory and swap space).  Therefore, the amount of memory to be
455  * used is either the limit imposed by the user during mount time or the
456  * amount of available memory, whichever is lower.  To avoid consuming all
457  * the memory for a given mount point, the system will always reserve a
458  * minimum of TMPFS_PAGES_RESERVED pages, which is also taken into account
459  * by this macro (see above). */
460 static __inline size_t
461 TMPFS_PAGES_MAX(struct tmpfs_mount *tmp)
462 {
463         size_t freepages;
464
465         freepages = tmpfs_mem_info();
466         freepages -= freepages < TMPFS_PAGES_RESERVED ? 
467             freepages : TMPFS_PAGES_RESERVED;
468
469         return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used);
470 }
471
472 /* Returns the available space for the given file system. */
473 #define TMPFS_META_SIZE(tmp) ((tmp)->tm_nodes_inuse * (sizeof(struct tmpfs_node) \
474                                 + sizeof(struct dirent)))
475 #define TMPFS_PAGES_AVAIL(tmp) (TMPFS_PAGES_MAX(tmp) - (tmp)->tm_pages_used - \
476                                 TMPFS_META_SIZE(tmp) / PAGE_SIZE - 1) 
477
478 #endif
479
480 /* --------------------------------------------------------------------- */
481
482 /*
483  * Macros/functions to convert from generic data structures to tmpfs
484  * specific ones.
485  */
486
487 static inline
488 struct tmpfs_mount *
489 VFS_TO_TMPFS(struct mount *mp)
490 {
491         struct tmpfs_mount *tmp;
492
493         MPASS((mp) != NULL && (mp)->mnt_data != NULL);
494         tmp = (struct tmpfs_mount *)(mp)->mnt_data;
495         return tmp;
496 }
497
498 static inline
499 struct tmpfs_node *
500 VP_TO_TMPFS_NODE(struct vnode *vp)
501 {
502         struct tmpfs_node *node;
503
504         MPASS((vp) != NULL && (vp)->v_data != NULL);
505         node = (struct tmpfs_node *)vp->v_data;
506         return node;
507 }
508
509 static inline
510 struct tmpfs_node *
511 VP_TO_TMPFS_DIR(struct vnode *vp)
512 {
513         struct tmpfs_node *node;
514
515         node = VP_TO_TMPFS_NODE(vp);
516         TMPFS_VALIDATE_DIR(node);
517         return node;
518 }
519
520 /* ---------------------------------------------------------------------
521  * USER AND KERNEL DEFINITIONS
522  * --------------------------------------------------------------------- */
523
524 /*
525  * This structure is used to communicate mount parameters between userland
526  * and kernel space.
527  */
528 #define TMPFS_ARGS_VERSION      1
529 struct tmpfs_args {
530         int                     ta_version;
531
532         /* Size counters. */
533         ino_t                   ta_nodes_max;
534         off_t                   ta_size_max;
535
536         /* Root node attributes. */
537         uid_t                   ta_root_uid;
538         gid_t                   ta_root_gid;
539         mode_t                  ta_root_mode;
540
541 };
542 #endif /* _FS_TMPFS_TMPFS_H_ */