Tue Jun 22 18:32:08 2010 UTC ()
Replace tmpfs_pool custom allocator code with a simpler layer for memory
accounting.  Use wired memory (which can be limited) for meta-data, and
kmem(9) for string allocations.

Close PR/31944.  Fix PR/38361 while here.  OK ad@.


(rmind)
diff -r1.6 -r1.7 src/sys/fs/tmpfs/TODO
diff -r1.3 -r1.4 src/sys/fs/tmpfs/files.tmpfs
diff -r1.37 -r1.38 src/sys/fs/tmpfs/tmpfs.h
diff -r0 -r1.1 src/sys/fs/tmpfs/tmpfs_mem.c
diff -r1.14 -r0 src/sys/fs/tmpfs/tmpfs_pool.c
diff -r1.7 -r0 src/sys/fs/tmpfs/tmpfs_pool.h
diff -r1.56 -r1.57 src/sys/fs/tmpfs/tmpfs_subr.c
diff -r1.44 -r1.45 src/sys/fs/tmpfs/tmpfs_vfsops.c
diff -r1.69 -r1.70 src/sys/fs/tmpfs/tmpfs_vnops.c
diff -r1.1 -r1.2 src/sys/modules/tmpfs/Makefile
diff -r1.3 -r1.4 src/sys/rump/fs/lib/libtmpfs/Makefile

cvs diff -r1.6 -r1.7 src/sys/fs/tmpfs/TODO (expand / switch to unified diff)

--- src/sys/fs/tmpfs/TODO 2006/11/09 15:06:03 1.6
+++ src/sys/fs/tmpfs/TODO 2010/06/22 18:32:07 1.7
@@ -1,18 +1,13 @@ @@ -1,18 +1,13 @@
1- File meta-data is stored using memory pools. These use, at the moment, 
2 wired kernel memory, which is not acceptable because it is easy to turn 
3 the system unstable by exhausting it. Therefore, a pool allocator that 
4 uses anonymous memory has to be written. 
5 
6- Verify that file holes work (they should, but must be checked). Add a 1- Verify that file holes work (they should, but must be checked). Add a
7 regression test for this feature. 2 regression test for this feature.
8 3
9- Fix and complete code marked with `XXX' and `TODO' tags. 4- Fix and complete code marked with `XXX' and `TODO' tags.
10 5
11- Adjust code style - remove the /* ---- */ markers and use standard 6- Adjust code style - remove the /* ---- */ markers and use standard
12 struct vop_*_args assignment into *ap with comment like: 7 struct vop_*_args assignment into *ap with comment like:
13 struct vop_link_args /* { 8 struct vop_link_args /* {
14 struct vnode *a_dvp; 9 struct vnode *a_dvp;
15 struct vnode *a_vp; 10 struct vnode *a_vp;
16 struct componentname *a_cnp; 11 struct componentname *a_cnp;
17 } */ *ap = v; 12 } */ *ap = v;
18 13

cvs diff -r1.3 -r1.4 src/sys/fs/tmpfs/files.tmpfs (expand / switch to unified diff)

--- src/sys/fs/tmpfs/files.tmpfs 2010/03/02 16:43:48 1.3
+++ src/sys/fs/tmpfs/files.tmpfs 2010/06/22 18:32:07 1.4
@@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
1# $NetBSD: files.tmpfs,v 1.3 2010/03/02 16:43:48 pooka Exp $ 1# $NetBSD: files.tmpfs,v 1.4 2010/06/22 18:32:07 rmind Exp $
2 2
3deffs TMPFS 3deffs TMPFS
4 4
5file fs/tmpfs/tmpfs_fifoops.c tmpfs 5file fs/tmpfs/tmpfs_fifoops.c tmpfs
6file fs/tmpfs/tmpfs_pool.c tmpfs 6file fs/tmpfs/tmpfs_mem.c tmpfs
7file fs/tmpfs/tmpfs_specops.c tmpfs 7file fs/tmpfs/tmpfs_specops.c tmpfs
8file fs/tmpfs/tmpfs_subr.c tmpfs 8file fs/tmpfs/tmpfs_subr.c tmpfs
9file fs/tmpfs/tmpfs_vfsops.c tmpfs 9file fs/tmpfs/tmpfs_vfsops.c tmpfs
10file fs/tmpfs/tmpfs_vnops.c tmpfs 10file fs/tmpfs/tmpfs_vnops.c tmpfs

cvs diff -r1.37 -r1.38 src/sys/fs/tmpfs/tmpfs.h (expand / switch to unified diff)

--- src/sys/fs/tmpfs/tmpfs.h 2008/07/29 09:10:09 1.37
+++ src/sys/fs/tmpfs/tmpfs.h 2010/06/22 18:32:07 1.38
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: tmpfs.h,v 1.37 2008/07/29 09:10:09 pooka Exp $ */ 1/* $NetBSD: tmpfs.h,v 1.38 2010/06/22 18:32:07 rmind Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. 4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 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 8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program. 9 * 2005 program.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -25,39 +25,30 @@ @@ -25,39 +25,30 @@
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33#ifndef _FS_TMPFS_TMPFS_H_ 33#ifndef _FS_TMPFS_TMPFS_H_
34#define _FS_TMPFS_TMPFS_H_ 34#define _FS_TMPFS_TMPFS_H_
35 35
36#include <sys/dirent.h> 36#include <sys/dirent.h>
37#include <sys/mount.h> 37#include <sys/mount.h>
 38#include <sys/pool.h>
38#include <sys/queue.h> 39#include <sys/queue.h>
39#include <sys/vnode.h> 40#include <sys/vnode.h>
40 41
41/* --------------------------------------------------------------------- */ 
42/* For the kernel and anyone who likes peeking into kernel memory */ 
43/* --------------------------------------------------------------------- */ 
44 
45#if defined(_KERNEL) 
46#include <fs/tmpfs/tmpfs_pool.h> 
47#endif /* defined(_KERNEL) */ 
48 
49/* --------------------------------------------------------------------- */ 
50 
51/* 42/*
52 * Internal representation of a tmpfs directory entry. 43 * Internal representation of a tmpfs directory entry.
53 */ 44 */
54struct tmpfs_dirent { 45struct tmpfs_dirent {
55 TAILQ_ENTRY(tmpfs_dirent) td_entries; 46 TAILQ_ENTRY(tmpfs_dirent) td_entries;
56 47
57 /* Length of the name stored in this directory entry. This avoids 48 /* Length of the name stored in this directory entry. This avoids
58 * the need to recalculate it every time the name is used. */ 49 * the need to recalculate it every time the name is used. */
59 uint16_t td_namelen; 50 uint16_t td_namelen;
60 51
61 /* The name of the entry, allocated from a string pool. This 52 /* The name of the entry, allocated from a string pool. This
62 * string is not required to be zero-terminated; therefore, the 53 * string is not required to be zero-terminated; therefore, the
63 * td_namelen field must always be used when accessing its value. */ 54 * td_namelen field must always be used when accessing its value. */
@@ -271,64 +262,56 @@ struct tmpfs_node { @@ -271,64 +262,56 @@ struct tmpfs_node {
271 } tn_reg; 262 } tn_reg;
272 } tn_spec; 263 } tn_spec;
273}; 264};
274 265
275#if defined(_KERNEL) 266#if defined(_KERNEL)
276LIST_HEAD(tmpfs_node_list, tmpfs_node); 267LIST_HEAD(tmpfs_node_list, tmpfs_node);
277 268
278/* --------------------------------------------------------------------- */ 269/* --------------------------------------------------------------------- */
279 270
280/* 271/*
281 * Internal representation of a tmpfs mount point. 272 * Internal representation of a tmpfs mount point.
282 */ 273 */
283struct tmpfs_mount { 274struct tmpfs_mount {
284 /* Maximum number of memory pages available for use by the file 275 /* Limit and number of bytes in use by the file system. */
285 * system, set during mount time. This variable must never be 276 uint64_t tm_mem_limit;
286 * used directly as it may be bigger than the current amount of 277 uint64_t tm_bytes_used;
287 * free memory; in the extreme case, it will hold the SIZE_MAX 278 kmutex_t tm_acc_lock;
288 * value. Instead, use the TMPFS_PAGES_MAX macro. */ 
289 unsigned int tm_pages_max; 
290 
291 /* Number of pages in use by the file system. Cannot be bigger 
292 * than the value returned by TMPFS_PAGES_MAX in any case. */ 
293 unsigned int tm_pages_used; 
294 279
295 /* Pointer to the node representing the root directory of this 280 /* Pointer to the node representing the root directory of this
296 * file system. */ 281 * file system. */
297 struct tmpfs_node * tm_root; 282 struct tmpfs_node * tm_root;
298 283
299 /* Maximum number of possible nodes for this file system; set 284 /* Maximum number of possible nodes for this file system; set
300 * during mount time. We need a hard limit on the maximum number 285 * during mount time. We need a hard limit on the maximum number
301 * of nodes to avoid allocating too much of them; their objects 286 * of nodes to avoid allocating too much of them; their objects
302 * cannot be released until the file system is unmounted. 287 * cannot be released until the file system is unmounted.
303 * Otherwise, we could easily run out of memory by creating lots 288 * Otherwise, we could easily run out of memory by creating lots
304 * of empty files and then simply removing them. */ 289 * of empty files and then simply removing them. */
305 unsigned int tm_nodes_max; 290 unsigned int tm_nodes_max;
306 291
307 /* Number of nodes currently allocated. This number only grows. 292 /* Number of nodes currently allocated. This number only grows.
308 * When it reaches tm_nodes_max, no more new nodes can be allocated. 293 * When it reaches tm_nodes_max, no more new nodes can be allocated.
309 * Of course, the old, unused ones can be reused. */ 294 * Of course, the old, unused ones can be reused. */
310 unsigned int tm_nodes_cnt; 295 unsigned int tm_nodes_cnt;
311 296
312 /* Node list. */ 297 /* Node list. */
313 kmutex_t tm_lock; 298 kmutex_t tm_lock;
314 struct tmpfs_node_list tm_nodes; 299 struct tmpfs_node_list tm_nodes;
315 300
316 /* Pools used to store file system meta data. These are not shared 301 char tm_dwchan[32];
317 * across several instances of tmpfs for the reasons described in 302 struct pool tm_dirent_pool;
318 * tmpfs_pool.c. */ 303 char tm_nwchan[32];
319 struct tmpfs_pool tm_dirent_pool; 304 struct pool tm_node_pool;
320 struct tmpfs_pool tm_node_pool; 
321 struct tmpfs_str_pool tm_str_pool; 
322}; 305};
323 306
324/* --------------------------------------------------------------------- */ 307/* --------------------------------------------------------------------- */
325 308
326/* 309/*
327 * This structure maps a file identifier to a tmpfs node. Used by the 310 * This structure maps a file identifier to a tmpfs node. Used by the
328 * NFS code. 311 * NFS code.
329 */ 312 */
330struct tmpfs_fid { 313struct tmpfs_fid {
331 uint16_t tf_len; 314 uint16_t tf_len;
332 uint16_t tf_pad; 315 uint16_t tf_pad;
333 uint32_t tf_gen; 316 uint32_t tf_gen;
334 ino_t tf_id; 317 ino_t tf_id;
@@ -351,41 +334,63 @@ void tmpfs_free_dirent(struct tmpfs_moun @@ -351,41 +334,63 @@ void tmpfs_free_dirent(struct tmpfs_moun
351int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **); 334int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **);
352void tmpfs_free_vp(struct vnode *); 335void tmpfs_free_vp(struct vnode *);
353int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 336int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
354 struct componentname *, char *); 337 struct componentname *, char *);
355void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *); 338void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
356void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *); 339void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
357struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node, 340struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node,
358 struct componentname *cnp); 341 struct componentname *cnp);
359int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); 342int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
360int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); 343int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
361struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); 344struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
362int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *); 345int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
363int tmpfs_reg_resize(struct vnode *, off_t); 346int tmpfs_reg_resize(struct vnode *, off_t);
364size_t tmpfs_mem_info(bool); 
365int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *); 347int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *);
366int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *); 348int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
367int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *); 349int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *);
368int tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct lwp *); 350int tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct lwp *);
369int tmpfs_chtimes(struct vnode *, const struct timespec *, 351int tmpfs_chtimes(struct vnode *, const struct timespec *,
370 const struct timespec *, const struct timespec *, int, kauth_cred_t, 352 const struct timespec *, const struct timespec *, int, kauth_cred_t,
371 struct lwp *); 353 struct lwp *);
372void tmpfs_itimes(struct vnode *, const struct timespec *, 354void tmpfs_itimes(struct vnode *, const struct timespec *,
373 const struct timespec *, const struct timespec *); 355 const struct timespec *, const struct timespec *);
374 356
375void tmpfs_update(struct vnode *, const struct timespec *, 357void tmpfs_update(struct vnode *, const struct timespec *,
376 const struct timespec *, const struct timespec *, int); 358 const struct timespec *, const struct timespec *, int);
377int tmpfs_truncate(struct vnode *, off_t); 359int tmpfs_truncate(struct vnode *, off_t);
378 360
 361/*
 362 * Prototypes for tmpfs_mem.c.
 363 */
 364
 365void tmpfs_mntmem_init(struct tmpfs_mount *, uint64_t);
 366void tmpfs_mntmem_destroy(struct tmpfs_mount *);
 367
 368size_t tmpfs_mem_info(bool);
 369uint64_t tmpfs_bytes_max(struct tmpfs_mount *);
 370size_t tmpfs_pages_avail(struct tmpfs_mount *);
 371bool tmpfs_mem_incr(struct tmpfs_mount *, size_t);
 372void tmpfs_mem_decr(struct tmpfs_mount *, size_t);
 373
 374struct tmpfs_dirent *tmpfs_dirent_get(struct tmpfs_mount *);
 375void tmpfs_dirent_put(struct tmpfs_mount *, struct tmpfs_dirent *);
 376
 377struct tmpfs_node *tmpfs_node_get(struct tmpfs_mount *);
 378void tmpfs_node_put(struct tmpfs_mount *, struct tmpfs_node *);
 379
 380char * tmpfs_strname_alloc(struct tmpfs_mount *, size_t);
 381void tmpfs_strname_free(struct tmpfs_mount *, char *, size_t);
 382bool tmpfs_strname_neqlen(struct componentname *, struct componentname *);
 383
379/* --------------------------------------------------------------------- */ 384/* --------------------------------------------------------------------- */
380 385
381/* 386/*
382 * Convenience macros to simplify some logical expressions. 387 * Convenience macros to simplify some logical expressions.
383 */ 388 */
384#define IMPLIES(a, b) (!(a) || (b)) 389#define IMPLIES(a, b) (!(a) || (b))
385#define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a)) 390#define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
386 391
387/* --------------------------------------------------------------------- */ 392/* --------------------------------------------------------------------- */
388 393
389/* 394/*
390 * Checks that the directory entry pointed by 'de' matches the name 'name' 395 * Checks that the directory entry pointed by 'de' matches the name 'name'
391 * with a length of 'len'. 396 * with a length of 'len'.
@@ -408,56 +413,26 @@ int tmpfs_truncate(struct vnode *, off_t @@ -408,56 +413,26 @@ int tmpfs_truncate(struct vnode *, off_t
408 (node)->tn_spec.tn_dir.tn_readdir_lastn); 413 (node)->tn_spec.tn_dir.tn_readdir_lastn);
409 414
410/* --------------------------------------------------------------------- */ 415/* --------------------------------------------------------------------- */
411 416
412/* 417/*
413 * Memory management stuff. 418 * Memory management stuff.
414 */ 419 */
415 420
416/* Amount of memory pages to reserve for the system (e.g., to not use by 421/* Amount of memory pages to reserve for the system (e.g., to not use by
417 * tmpfs). 422 * tmpfs).
418 * XXX: Should this be tunable through sysctl, for instance? */ 423 * XXX: Should this be tunable through sysctl, for instance? */
419#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 424#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
420 425
421/* Returns the maximum size allowed for a tmpfs file system. This macro 
422 * must be used instead of directly retrieving the value from tm_pages_max. 
423 * The reason is that the size of a tmpfs file system is dynamic: it lets 
424 * the user store files as long as there is enough free memory (including 
425 * physical memory and swap space). Therefore, the amount of memory to be 
426 * used is either the limit imposed by the user during mount time or the 
427 * amount of available memory, whichever is lower. To avoid consuming all 
428 * the memory for a given mount point, the system will always reserve a 
429 * minimum of TMPFS_PAGES_RESERVED pages, which is also taken into account 
430 * by this macro (see above). */ 
431static __inline size_t 
432TMPFS_PAGES_MAX(struct tmpfs_mount *tmp) 
433{ 
434 size_t freepages; 
435 
436 freepages = tmpfs_mem_info(false); 
437 if (freepages < TMPFS_PAGES_RESERVED) 
438 freepages = 0; 
439 else 
440 freepages -= TMPFS_PAGES_RESERVED; 
441 
442 return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used); 
443} 
444 
445/* Returns the available space for the given file system. */ 
446#define TMPFS_PAGES_AVAIL(tmp) \ 
447 ((ssize_t)(TMPFS_PAGES_MAX(tmp) - (tmp)->tm_pages_used)) 
448 
449/* --------------------------------------------------------------------- */ 
450 
451/* 426/*
452 * Macros/functions to convert from generic data structures to tmpfs 427 * Macros/functions to convert from generic data structures to tmpfs
453 * specific ones. 428 * specific ones.
454 */ 429 */
455 430
456static __inline 431static __inline
457struct tmpfs_mount * 432struct tmpfs_mount *
458VFS_TO_TMPFS(struct mount *mp) 433VFS_TO_TMPFS(struct mount *mp)
459{ 434{
460 struct tmpfs_mount *tmp; 435 struct tmpfs_mount *tmp;
461 436
462#ifdef KASSERT 437#ifdef KASSERT
463 KASSERT((mp) != NULL && (mp)->mnt_data != NULL); 438 KASSERT((mp) != NULL && (mp)->mnt_data != NULL);

File Added: src/sys/fs/tmpfs/tmpfs_mem.c
/*	$NetBSD: tmpfs_mem.c,v 1.1 2010/06/22 18:32:07 rmind Exp $	*/

/*
 * Copyright (c) 2010 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * tmpfs memory allocation routines.
 * Implements memory usage accounting and limiting.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tmpfs_mem.c,v 1.1 2010/06/22 18:32:07 rmind Exp $");

#include <sys/param.h>
#include <sys/atomic.h>
#include <sys/kmem.h>
#include <sys/namei.h>
#include <sys/pool.h>

#include <fs/tmpfs/tmpfs.h>

void
tmpfs_mntmem_init(struct tmpfs_mount *mp, uint64_t memlimit)
{

	sprintf(mp->tm_dwchan, "tmpfs_dirent_%p", mp);
	pool_init(&mp->tm_dirent_pool, sizeof(struct tmpfs_dirent), 0, 0, 0,
	    mp->tm_dwchan, &pool_allocator_nointr, IPL_NONE);

	sprintf(mp->tm_nwchan, "tmpfs_node_%p", mp);
	pool_init(&mp->tm_node_pool, sizeof(struct tmpfs_node), 0, 0, 0,
	    mp->tm_dwchan, &pool_allocator_nointr, IPL_NONE);

	mutex_init(&mp->tm_acc_lock, MUTEX_DEFAULT, IPL_NONE);
	mp->tm_mem_limit = memlimit;
	mp->tm_bytes_used = 0;
}

void
tmpfs_mntmem_destroy(struct tmpfs_mount *mp)
{

	KASSERT(mp->tm_bytes_used == 0);
	mutex_destroy(&mp->tm_acc_lock);
	pool_destroy(&mp->tm_dirent_pool);
	pool_destroy(&mp->tm_node_pool);
}

/*
 * tmpfs_mem_info: return the number of available memory pages.
 *
 * => If 'total' is true, then return _total_ amount of pages.
 * => If false, then return the amount of _free_ memory pages.
 *
 * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
 * excessive memory usage.
 */
size_t
tmpfs_mem_info(bool total)
{
	size_t size = 0;

	/* XXX: unlocked */
	size += uvmexp.swpgavail;
	if (!total) {
		size -= uvmexp.swpgonly;
	}
	size += uvmexp.free;
	size += uvmexp.filepages;
	if (size > uvmexp.wired) {
		size -= uvmexp.wired;
	} else {
		size = 0;
	}
	return size;
}

uint64_t
tmpfs_bytes_max(struct tmpfs_mount *mp)
{
	size_t freepages = tmpfs_mem_info(false);
	uint64_t avail_mem;

	if (freepages < TMPFS_PAGES_RESERVED) {
		freepages = 0;
	} else {
		freepages -= TMPFS_PAGES_RESERVED;
	}
	avail_mem = round_page(mp->tm_bytes_used) + (freepages << PAGE_SHIFT);
	return min(mp->tm_mem_limit, avail_mem);
}

size_t
tmpfs_pages_avail(struct tmpfs_mount *mp)
{

	return (tmpfs_bytes_max(mp) - mp->tm_bytes_used) >> PAGE_SHIFT;
}

bool
tmpfs_mem_incr(struct tmpfs_mount *mp, size_t sz)
{
	const uint64_t lim = tmpfs_bytes_max(mp);

	mutex_enter(&mp->tm_acc_lock);
	if (mp->tm_bytes_used + sz >= lim) {
		mutex_exit(&mp->tm_acc_lock);
		return false;
	}
	mp->tm_bytes_used += sz;
	mutex_exit(&mp->tm_acc_lock);
	return true;
}

void
tmpfs_mem_decr(struct tmpfs_mount *mp, size_t sz)
{

	mutex_enter(&mp->tm_acc_lock);
	KASSERT(mp->tm_bytes_used >= sz);
	mp->tm_bytes_used -= sz;
	mutex_exit(&mp->tm_acc_lock);
}

struct tmpfs_dirent *
tmpfs_dirent_get(struct tmpfs_mount *mp)
{

	if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_dirent))) {
		return NULL;
	}
	return pool_get(&mp->tm_dirent_pool, PR_WAITOK);
}

void
tmpfs_dirent_put(struct tmpfs_mount *mp, struct tmpfs_dirent *de)
{

	tmpfs_mem_decr(mp, sizeof(struct tmpfs_dirent));
	pool_put(&mp->tm_dirent_pool, de);
}

struct tmpfs_node *
tmpfs_node_get(struct tmpfs_mount *mp)
{

	if (!tmpfs_mem_incr(mp, sizeof(struct tmpfs_node))) {
		return NULL;
	}
	return pool_get(&mp->tm_node_pool, PR_WAITOK);
}

void
tmpfs_node_put(struct tmpfs_mount *mp, struct tmpfs_node *tn)
{

	tmpfs_mem_decr(mp, sizeof(struct tmpfs_node));
	pool_put(&mp->tm_node_pool, tn);
}

/*
 * Quantum size to round-up the tmpfs names in order to reduce re-allocations.
 */

#define	TMPFS_NAME_QUANTUM	(32)

char *
tmpfs_strname_alloc(struct tmpfs_mount *mp, size_t len)
{
	const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);

	KASSERT(sz > 0 && sz <= 1024);
	if (!tmpfs_mem_incr(mp, sz)) {
		return NULL;
	}
	return kmem_alloc(sz, KM_SLEEP);
}

void
tmpfs_strname_free(struct tmpfs_mount *mp, char *str, size_t len)
{
	const size_t sz = roundup2(len, TMPFS_NAME_QUANTUM);

	KASSERT(sz > 0 && sz <= 1024);
	tmpfs_mem_decr(mp, sz);
	kmem_free(str, sz);
}

bool
tmpfs_strname_neqlen(struct componentname *fcnp, struct componentname *tcnp)
{
	const size_t fln = roundup2(fcnp->cn_namelen, TMPFS_NAME_QUANTUM);
	const size_t tln = roundup2(tcnp->cn_namelen, TMPFS_NAME_QUANTUM);

	return (fln != tln) || memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fln);
}

File Deleted: src/sys/fs/tmpfs/Attic/tmpfs_pool.c

File Deleted: src/sys/fs/tmpfs/Attic/tmpfs_pool.h

cvs diff -r1.56 -r1.57 src/sys/fs/tmpfs/tmpfs_subr.c (expand / switch to unified diff)

--- src/sys/fs/tmpfs/tmpfs_subr.c 2009/11/11 09:59:41 1.56
+++ src/sys/fs/tmpfs/tmpfs_subr.c 2010/06/22 18:32:08 1.57
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: tmpfs_subr.c,v 1.56 2009/11/11 09:59:41 rmind Exp $ */ 1/* $NetBSD: tmpfs_subr.c,v 1.57 2010/06/22 18:32:08 rmind Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. 4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 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 8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program. 9 * 2005 program.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -25,27 +25,27 @@ @@ -25,27 +25,27 @@
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33/* 33/*
34 * Efficient memory file system supporting functions. 34 * Efficient memory file system supporting functions.
35 */ 35 */
36 36
37#include <sys/cdefs.h> 37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.56 2009/11/11 09:59:41 rmind Exp $"); 38__KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.57 2010/06/22 18:32:08 rmind Exp $");
39 39
40#include <sys/param.h> 40#include <sys/param.h>
41#include <sys/dirent.h> 41#include <sys/dirent.h>
42#include <sys/event.h> 42#include <sys/event.h>
43#include <sys/kmem.h> 43#include <sys/kmem.h>
44#include <sys/mount.h> 44#include <sys/mount.h>
45#include <sys/namei.h> 45#include <sys/namei.h>
46#include <sys/time.h> 46#include <sys/time.h>
47#include <sys/stat.h> 47#include <sys/stat.h>
48#include <sys/systm.h> 48#include <sys/systm.h>
49#include <sys/swap.h> 49#include <sys/swap.h>
50#include <sys/vnode.h> 50#include <sys/vnode.h>
51#include <sys/kauth.h> 51#include <sys/kauth.h>
@@ -97,27 +97,27 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp @@ -97,27 +97,27 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
97 KASSERT(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR)); 97 KASSERT(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR));
98 98
99 KASSERT(IFF(type == VLNK, target != NULL)); 99 KASSERT(IFF(type == VLNK, target != NULL));
100 KASSERT(IFF(type == VBLK || type == VCHR, rdev != VNOVAL)); 100 KASSERT(IFF(type == VBLK || type == VCHR, rdev != VNOVAL));
101 101
102 KASSERT(uid != VNOVAL && gid != VNOVAL && mode != VNOVAL); 102 KASSERT(uid != VNOVAL && gid != VNOVAL && mode != VNOVAL);
103 103
104 nnode = NULL; 104 nnode = NULL;
105 if (atomic_inc_uint_nv(&tmp->tm_nodes_cnt) >= tmp->tm_nodes_max) { 105 if (atomic_inc_uint_nv(&tmp->tm_nodes_cnt) >= tmp->tm_nodes_max) {
106 atomic_dec_uint(&tmp->tm_nodes_cnt); 106 atomic_dec_uint(&tmp->tm_nodes_cnt);
107 return ENOSPC; 107 return ENOSPC;
108 } 108 }
109 109
110 nnode = (struct tmpfs_node *)TMPFS_POOL_GET(&tmp->tm_node_pool, 0); 110 nnode = tmpfs_node_get(tmp);
111 if (nnode == NULL) { 111 if (nnode == NULL) {
112 atomic_dec_uint(&tmp->tm_nodes_cnt); 112 atomic_dec_uint(&tmp->tm_nodes_cnt);
113 return ENOSPC; 113 return ENOSPC;
114 } 114 }
115 115
116 /* 116 /*
117 * XXX Where the pool is backed by a map larger than (4GB * 117 * XXX Where the pool is backed by a map larger than (4GB *
118 * sizeof(*nnode)), this may produce duplicate inode numbers 118 * sizeof(*nnode)), this may produce duplicate inode numbers
119 * for applications that do not understand 64-bit ino_t. 119 * for applications that do not understand 64-bit ino_t.
120 */ 120 */
121 nnode->tn_id = (ino_t)((uintptr_t)nnode / sizeof(*nnode)); 121 nnode->tn_id = (ino_t)((uintptr_t)nnode / sizeof(*nnode));
122 nnode->tn_gen = arc4random(); 122 nnode->tn_gen = arc4random();
123 123
@@ -154,30 +154,30 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp @@ -154,30 +154,30 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
154 nnode->tn_spec.tn_dir.tn_readdir_lastp = NULL; 154 nnode->tn_spec.tn_dir.tn_readdir_lastp = NULL;
155 nnode->tn_links++; 155 nnode->tn_links++;
156 break; 156 break;
157 157
158 case VFIFO: 158 case VFIFO:
159 /* FALLTHROUGH */ 159 /* FALLTHROUGH */
160 case VSOCK: 160 case VSOCK:
161 break; 161 break;
162 162
163 case VLNK: 163 case VLNK:
164 KASSERT(strlen(target) < MAXPATHLEN); 164 KASSERT(strlen(target) < MAXPATHLEN);
165 nnode->tn_size = strlen(target); 165 nnode->tn_size = strlen(target);
166 nnode->tn_spec.tn_lnk.tn_link = 166 nnode->tn_spec.tn_lnk.tn_link =
167 tmpfs_str_pool_get(&tmp->tm_str_pool, nnode->tn_size, 0); 167 tmpfs_strname_alloc(tmp, nnode->tn_size);
168 if (nnode->tn_spec.tn_lnk.tn_link == NULL) { 168 if (nnode->tn_spec.tn_lnk.tn_link == NULL) {
169 atomic_dec_uint(&tmp->tm_nodes_cnt); 169 atomic_dec_uint(&tmp->tm_nodes_cnt);
170 TMPFS_POOL_PUT(&tmp->tm_node_pool, nnode); 170 tmpfs_node_put(tmp, nnode);
171 return ENOSPC; 171 return ENOSPC;
172 } 172 }
173 memcpy(nnode->tn_spec.tn_lnk.tn_link, target, nnode->tn_size); 173 memcpy(nnode->tn_spec.tn_lnk.tn_link, target, nnode->tn_size);
174 break; 174 break;
175 175
176 case VREG: 176 case VREG:
177 nnode->tn_spec.tn_reg.tn_aobj = 177 nnode->tn_spec.tn_reg.tn_aobj =
178 uao_create(INT32_MAX - PAGE_SIZE, 0); 178 uao_create(INT32_MAX - PAGE_SIZE, 0);
179 nnode->tn_spec.tn_reg.tn_aobj_pages = 0; 179 nnode->tn_spec.tn_reg.tn_aobj_pages = 0;
180 break; 180 break;
181 181
182 default: 182 default:
183 KASSERT(0); 183 KASSERT(0);
@@ -205,80 +205,84 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp @@ -205,80 +205,84 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
205 * kernel space. Furthermore, there is not need to provide such 205 * kernel space. Furthermore, there is not need to provide such
206 * functionality (recursive removal) because the only primitives offered 206 * functionality (recursive removal) because the only primitives offered
207 * to the user are the removal of empty directories and the deletion of 207 * to the user are the removal of empty directories and the deletion of
208 * individual files. 208 * individual files.
209 * 209 *
210 * Note that nodes are not really deleted; in fact, when a node has been 210 * Note that nodes are not really deleted; in fact, when a node has been
211 * allocated, it cannot be deleted during the whole life of the file 211 * allocated, it cannot be deleted during the whole life of the file
212 * system. Instead, they are moved to the available list and remain there 212 * system. Instead, they are moved to the available list and remain there
213 * until reused. 213 * until reused.
214 */ 214 */
215void 215void
216tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) 216tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
217{ 217{
 218 size_t objsz;
218 219
219 if (node->tn_type == VREG) { 
220 atomic_add_int(&tmp->tm_pages_used, 
221 -node->tn_spec.tn_reg.tn_aobj_pages); 
222 } 
223 atomic_dec_uint(&tmp->tm_nodes_cnt); 
224 mutex_enter(&tmp->tm_lock); 220 mutex_enter(&tmp->tm_lock);
225 LIST_REMOVE(node, tn_entries); 221 LIST_REMOVE(node, tn_entries);
226 mutex_exit(&tmp->tm_lock); 222 mutex_exit(&tmp->tm_lock);
 223 atomic_dec_uint(&tmp->tm_nodes_cnt);
227 224
228 switch (node->tn_type) { 225 switch (node->tn_type) {
229 case VLNK: 226 case VLNK:
230 tmpfs_str_pool_put(&tmp->tm_str_pool, 227 tmpfs_strname_free(tmp, node->tn_spec.tn_lnk.tn_link,
231 node->tn_spec.tn_lnk.tn_link, node->tn_size); 228 node->tn_size);
232 break; 229 break;
233 
234 case VREG: 230 case VREG:
235 if (node->tn_spec.tn_reg.tn_aobj != NULL) 231 /*
 232 * Calculate the size of node data, decrease the used-memory
 233 * counter, and destroy the memory object (if any).
 234 */
 235 objsz = PAGE_SIZE * node->tn_spec.tn_reg.tn_aobj_pages;
 236 if (objsz != 0) {
 237 tmpfs_mem_decr(tmp, objsz);
 238 }
 239 if (node->tn_spec.tn_reg.tn_aobj != NULL) {
236 uao_detach(node->tn_spec.tn_reg.tn_aobj); 240 uao_detach(node->tn_spec.tn_reg.tn_aobj);
 241 }
237 break; 242 break;
238 
239 default: 243 default:
240 break; 244 break;
241 } 245 }
242 246
243 mutex_destroy(&node->tn_vlock); 247 mutex_destroy(&node->tn_vlock);
244 TMPFS_POOL_PUT(&tmp->tm_node_pool, node); 248 tmpfs_node_put(tmp, node);
245} 249}
246 250
247/* --------------------------------------------------------------------- */ 251/* --------------------------------------------------------------------- */
248 252
249/* 253/*
250 * Allocates a new directory entry for the node node with a name of name. 254 * Allocates a new directory entry for the node node with a name of name.
251 * The new directory entry is returned in *de. 255 * The new directory entry is returned in *de.
252 * 256 *
253 * The link count of node is increased by one to reflect the new object 257 * The link count of node is increased by one to reflect the new object
254 * referencing it. This takes care of notifying kqueue listeners about 258 * referencing it. This takes care of notifying kqueue listeners about
255 * this change. 259 * this change.
256 * 260 *
257 * Returns zero on success or an appropriate error code on failure. 261 * Returns zero on success or an appropriate error code on failure.
258 */ 262 */
259int 263int
260tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node, 264tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
261 const char *name, uint16_t len, struct tmpfs_dirent **de) 265 const char *name, uint16_t len, struct tmpfs_dirent **de)
262{ 266{
263 struct tmpfs_dirent *nde; 267 struct tmpfs_dirent *nde;
264 268
265 nde = (struct tmpfs_dirent *)TMPFS_POOL_GET(&tmp->tm_dirent_pool, 0); 269 nde = tmpfs_dirent_get(tmp);
266 if (nde == NULL) 270 if (nde == NULL)
267 return ENOSPC; 271 return ENOSPC;
268 272
269 nde->td_name = tmpfs_str_pool_get(&tmp->tm_str_pool, len, 0); 273 nde->td_name = tmpfs_strname_alloc(tmp, len);
270 if (nde->td_name == NULL) { 274 if (nde->td_name == NULL) {
271 TMPFS_POOL_PUT(&tmp->tm_dirent_pool, nde); 275 tmpfs_dirent_put(tmp, nde);
272 return ENOSPC; 276 return ENOSPC;
273 } 277 }
274 nde->td_namelen = len; 278 nde->td_namelen = len;
275 memcpy(nde->td_name, name, len); 279 memcpy(nde->td_name, name, len);
276 nde->td_node = node; 280 nde->td_node = node;
277 281
278 node->tn_links++; 282 node->tn_links++;
279 if (node->tn_links > 1 && node->tn_vnode != NULL) 283 if (node->tn_links > 1 && node->tn_vnode != NULL)
280 VN_KNOTE(node->tn_vnode, NOTE_LINK); 284 VN_KNOTE(node->tn_vnode, NOTE_LINK);
281 *de = nde; 285 *de = nde;
282 286
283 return 0; 287 return 0;
284} 288}
@@ -307,28 +311,28 @@ tmpfs_free_dirent(struct tmpfs_mount *tm @@ -307,28 +311,28 @@ tmpfs_free_dirent(struct tmpfs_mount *tm
307 311
308 node = de->td_node; 312 node = de->td_node;
309 313
310 KASSERT(node->tn_links > 0); 314 KASSERT(node->tn_links > 0);
311 node->tn_links--; 315 node->tn_links--;
312 if (node->tn_vnode != NULL) 316 if (node->tn_vnode != NULL)
313 VN_KNOTE(node->tn_vnode, node->tn_links == 0 ? 317 VN_KNOTE(node->tn_vnode, node->tn_links == 0 ?
314 NOTE_DELETE : NOTE_LINK); 318 NOTE_DELETE : NOTE_LINK);
315 if (node->tn_type == VDIR) 319 if (node->tn_type == VDIR)
316 VN_KNOTE(node->tn_spec.tn_dir.tn_parent->tn_vnode, 320 VN_KNOTE(node->tn_spec.tn_dir.tn_parent->tn_vnode,
317 NOTE_LINK); 321 NOTE_LINK);
318 } 322 }
319 323
320 tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, de->td_namelen); 324 tmpfs_strname_free(tmp, de->td_name, de->td_namelen);
321 TMPFS_POOL_PUT(&tmp->tm_dirent_pool, de); 325 tmpfs_dirent_put(tmp, de);
322} 326}
323 327
324/* --------------------------------------------------------------------- */ 328/* --------------------------------------------------------------------- */
325 329
326/* 330/*
327 * Allocates a new vnode for the node node or returns a new reference to 331 * Allocates a new vnode for the node node or returns a new reference to
328 * an existing one if the node had already a vnode referencing it. The 332 * an existing one if the node had already a vnode referencing it. The
329 * resulting locked vnode is returned in *vpp. 333 * resulting locked vnode is returned in *vpp.
330 * 334 *
331 * Returns zero on success or an appropriate error code on failure. 335 * Returns zero on success or an appropriate error code on failure.
332 */ 336 */
333int 337int
334tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp) 338tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp)
@@ -845,128 +849,80 @@ tmpfs_dir_getdents(struct tmpfs_node *no @@ -845,128 +849,80 @@ tmpfs_dir_getdents(struct tmpfs_node *no
845 * Resizes the aobj associated to the regular file pointed to by vp to 849 * Resizes the aobj associated to the regular file pointed to by vp to
846 * the size newsize. 'vp' must point to a vnode that represents a regular 850 * the size newsize. 'vp' must point to a vnode that represents a regular
847 * file. 'newsize' must be positive. 851 * file. 'newsize' must be positive.
848 * 852 *
849 * If the file is extended, the appropriate kevent is raised. This does 853 * If the file is extended, the appropriate kevent is raised. This does
850 * not rise a write event though because resizing is not the same as 854 * not rise a write event though because resizing is not the same as
851 * writing. 855 * writing.
852 * 856 *
853 * Returns zero on success or an appropriate error code on failure. 857 * Returns zero on success or an appropriate error code on failure.
854 */ 858 */
855int 859int
856tmpfs_reg_resize(struct vnode *vp, off_t newsize) 860tmpfs_reg_resize(struct vnode *vp, off_t newsize)
857{ 861{
858 int error; 862 size_t newpages, oldpages;
859 unsigned int newpages, oldpages; 
860 struct tmpfs_mount *tmp; 863 struct tmpfs_mount *tmp;
861 struct tmpfs_node *node; 864 struct tmpfs_node *node;
862 off_t oldsize; 865 off_t oldsize;
863 866
864 KASSERT(vp->v_type == VREG); 867 KASSERT(vp->v_type == VREG);
865 KASSERT(newsize >= 0); 868 KASSERT(newsize >= 0);
866 869
867 node = VP_TO_TMPFS_NODE(vp); 870 node = VP_TO_TMPFS_NODE(vp);
868 tmp = VFS_TO_TMPFS(vp->v_mount); 871 tmp = VFS_TO_TMPFS(vp->v_mount);
869 872
870 /* Convert the old and new sizes to the number of pages needed to 
871 * store them. It may happen that we do not need to do anything 
872 * because the last allocated page can accommodate the change on 
873 * its own. */ 
874 oldsize = node->tn_size; 873 oldsize = node->tn_size;
875 oldpages = round_page(oldsize) / PAGE_SIZE; 874 oldpages = round_page(oldsize) >> PAGE_SHIFT;
 875 newpages = round_page(newsize) >> PAGE_SHIFT;
876 KASSERT(oldpages == node->tn_spec.tn_reg.tn_aobj_pages); 876 KASSERT(oldpages == node->tn_spec.tn_reg.tn_aobj_pages);
877 newpages = round_page(newsize) / PAGE_SIZE; 
878 877
879 if (newpages > oldpages && 878 if (newpages > oldpages) {
880 (ssize_t)(newpages - oldpages) > TMPFS_PAGES_AVAIL(tmp)) { 879 /* Increase the used-memory counter if getting extra pages. */
881 error = ENOSPC; 880 if (!tmpfs_mem_incr(tmp, (newpages - oldpages) << PAGE_SHIFT)) {
882 goto out; 881 return ENOSPC;
883 } 882 }
884 atomic_add_int(&tmp->tm_pages_used, newpages - oldpages); 883 } else if (newsize < oldsize) {
885 
886 if (newsize < oldsize) { 
887 int zerolen = MIN(round_page(newsize), node->tn_size) - newsize; 884 int zerolen = MIN(round_page(newsize), node->tn_size) - newsize;
888 885
889 /* 886 /* Zero out the truncated part of the last page. */
890 * zero out the truncated part of the last page. 
891 */ 
892 
893 uvm_vnp_zerorange(vp, newsize, zerolen); 887 uvm_vnp_zerorange(vp, newsize, zerolen);
894 } 888 }
895 889
896 node->tn_spec.tn_reg.tn_aobj_pages = newpages; 890 node->tn_spec.tn_reg.tn_aobj_pages = newpages;
897 node->tn_size = newsize; 891 node->tn_size = newsize;
898 uvm_vnp_setsize(vp, newsize); 892 uvm_vnp_setsize(vp, newsize);
899 893
900 /* 894 /*
901 * free "backing store" 895 * Free "backing store".
902 */ 896 */
903 
904 if (newpages < oldpages) { 897 if (newpages < oldpages) {
905 struct uvm_object *uobj; 898 struct uvm_object *uobj;
906 899
907 uobj = node->tn_spec.tn_reg.tn_aobj; 900 uobj = node->tn_spec.tn_reg.tn_aobj;
908 901
909 mutex_enter(&uobj->vmobjlock); 902 mutex_enter(&uobj->vmobjlock);
910 uao_dropswap_range(uobj, newpages, oldpages); 903 uao_dropswap_range(uobj, newpages, oldpages);
911 mutex_exit(&uobj->vmobjlock); 904 mutex_exit(&uobj->vmobjlock);
912 } 
913 905
914 error = 0; 906 /* Decrease the used-memory counter. */
 907 tmpfs_mem_decr(tmp, (oldpages - newpages) << PAGE_SHIFT);
 908 }
915 909
916 if (newsize > oldsize) 910 if (newsize > oldsize)
917 VN_KNOTE(vp, NOTE_EXTEND); 911 VN_KNOTE(vp, NOTE_EXTEND);
918 912
919out: 913 return 0;
920 return error; 
921} 
922 
923/* --------------------------------------------------------------------- */ 
924 
925/* 
926 * Returns information about the number of available memory pages, 
927 * including physical and virtual ones. 
928 * 
929 * If 'total' is true, the value returned is the total amount of memory 
930 * pages configured for the system (either in use or free). 
931 * If it is FALSE, the value returned is the amount of free memory pages. 
932 * 
933 * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid 
934 * excessive memory usage. 
935 * 
936 */ 
937size_t 
938tmpfs_mem_info(bool total) 
939{ 
940 size_t size; 
941 
942 size = 0; 
943 size += uvmexp.swpgavail; 
944 if (!total) { 
945 size -= uvmexp.swpgonly; 
946 } 
947 size += uvmexp.free; 
948 size += uvmexp.filepages; 
949 if (size > uvmexp.wired) { 
950 size -= uvmexp.wired; 
951 } else { 
952 size = 0; 
953 } 
954 
955 return size; 
956} 914}
957 915
958/* --------------------------------------------------------------------- */ 
959 
960/* 916/*
961 * Change flags of the given vnode. 917 * Change flags of the given vnode.
962 * Caller should execute tmpfs_update on vp after a successful execution. 918 * Caller should execute tmpfs_update on vp after a successful execution.
963 * The vnode must be locked on entry and remain locked on exit. 919 * The vnode must be locked on entry and remain locked on exit.
964 */ 920 */
965int 921int
966tmpfs_chflags(struct vnode *vp, int flags, kauth_cred_t cred, struct lwp *l) 922tmpfs_chflags(struct vnode *vp, int flags, kauth_cred_t cred, struct lwp *l)
967{ 923{
968 int error; 924 int error;
969 struct tmpfs_node *node; 925 struct tmpfs_node *node;
970 kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS; 926 kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
971 int fs_decision = 0; 927 int fs_decision = 0;
972 928

cvs diff -r1.44 -r1.45 src/sys/fs/tmpfs/tmpfs_vfsops.c (expand / switch to unified diff)

--- src/sys/fs/tmpfs/tmpfs_vfsops.c 2008/07/29 09:10:09 1.44
+++ src/sys/fs/tmpfs/tmpfs_vfsops.c 2010/06/22 18:32:08 1.45
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: tmpfs_vfsops.c,v 1.44 2008/07/29 09:10:09 pooka Exp $ */ 1/* $NetBSD: tmpfs_vfsops.c,v 1.45 2010/06/22 18:32:08 rmind Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. 4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 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 8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program. 9 * 2005 program.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -32,27 +32,27 @@ @@ -32,27 +32,27 @@
32 32
33/* 33/*
34 * Efficient memory file system. 34 * Efficient memory file system.
35 * 35 *
36 * tmpfs is a file system that uses NetBSD's virtual memory sub-system 36 * tmpfs is a file system that uses NetBSD's virtual memory sub-system
37 * (the well-known UVM) to store file data and metadata in an efficient 37 * (the well-known UVM) to store file data and metadata in an efficient
38 * way. This means that it does not follow the structure of an on-disk 38 * way. This means that it does not follow the structure of an on-disk
39 * file system because it simply does not need to. Instead, it uses 39 * file system because it simply does not need to. Instead, it uses
40 * memory-specific data structures and algorithms to automatically 40 * memory-specific data structures and algorithms to automatically
41 * allocate and release resources. 41 * allocate and release resources.
42 */ 42 */
43 43
44#include <sys/cdefs.h> 44#include <sys/cdefs.h>
45__KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.44 2008/07/29 09:10:09 pooka Exp $"); 45__KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.45 2010/06/22 18:32:08 rmind Exp $");
46 46
47#include <sys/param.h> 47#include <sys/param.h>
48#include <sys/types.h> 48#include <sys/types.h>
49#include <sys/kmem.h> 49#include <sys/kmem.h>
50#include <sys/mount.h> 50#include <sys/mount.h>
51#include <sys/stat.h> 51#include <sys/stat.h>
52#include <sys/systm.h> 52#include <sys/systm.h>
53#include <sys/vnode.h> 53#include <sys/vnode.h>
54#include <sys/proc.h> 54#include <sys/proc.h>
55#include <sys/module.h> 55#include <sys/module.h>
56 56
57#include <miscfs/genfs/genfs.h> 57#include <miscfs/genfs/genfs.h>
58#include <fs/tmpfs/tmpfs.h> 58#include <fs/tmpfs/tmpfs.h>
@@ -71,129 +71,116 @@ static int tmpfs_fhtovp(struct mount *,  @@ -71,129 +71,116 @@ static int tmpfs_fhtovp(struct mount *,
71static int tmpfs_vptofh(struct vnode *, struct fid *, size_t *); 71static int tmpfs_vptofh(struct vnode *, struct fid *, size_t *);
72static int tmpfs_statvfs(struct mount *, struct statvfs *); 72static int tmpfs_statvfs(struct mount *, struct statvfs *);
73static int tmpfs_sync(struct mount *, int, kauth_cred_t); 73static int tmpfs_sync(struct mount *, int, kauth_cred_t);
74static void tmpfs_init(void); 74static void tmpfs_init(void);
75static void tmpfs_done(void); 75static void tmpfs_done(void);
76static int tmpfs_snapshot(struct mount *, struct vnode *, 76static int tmpfs_snapshot(struct mount *, struct vnode *,
77 struct timespec *); 77 struct timespec *);
78 78
79/* --------------------------------------------------------------------- */ 79/* --------------------------------------------------------------------- */
80 80
81static int 81static int
82tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 82tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
83{ 83{
84 struct lwp *l = curlwp; 
85 int error; 
86 ino_t nodes; 
87 size_t pages; 
88 struct tmpfs_mount *tmp; 84 struct tmpfs_mount *tmp;
89 struct tmpfs_node *root; 85 struct tmpfs_node *root;
90 struct tmpfs_args *args = data; 86 struct tmpfs_args *args = data;
 87 uint64_t memlimit;
 88 ino_t nodes;
 89 int error;
91 90
92 if (*data_len < sizeof *args) 91 if (*data_len < sizeof *args)
93 return EINVAL; 92 return EINVAL;
94 93
95 /* Handle retrieval of mount point arguments. */ 94 /* Handle retrieval of mount point arguments. */
96 if (mp->mnt_flag & MNT_GETARGS) { 95 if (mp->mnt_flag & MNT_GETARGS) {
97 if (mp->mnt_data == NULL) 96 if (mp->mnt_data == NULL)
98 return EIO; 97 return EIO;
99 tmp = VFS_TO_TMPFS(mp); 98 tmp = VFS_TO_TMPFS(mp);
100 99
101 args->ta_version = TMPFS_ARGS_VERSION; 100 args->ta_version = TMPFS_ARGS_VERSION;
102 args->ta_nodes_max = tmp->tm_nodes_max; 101 args->ta_nodes_max = tmp->tm_nodes_max;
103 args->ta_size_max = tmp->tm_pages_max * PAGE_SIZE; 102 args->ta_size_max = tmp->tm_mem_limit;
104 103
105 root = tmp->tm_root; 104 root = tmp->tm_root;
106 args->ta_root_uid = root->tn_uid; 105 args->ta_root_uid = root->tn_uid;
107 args->ta_root_gid = root->tn_gid; 106 args->ta_root_gid = root->tn_gid;
108 args->ta_root_mode = root->tn_mode; 107 args->ta_root_mode = root->tn_mode;
109 108
110 *data_len = sizeof *args; 109 *data_len = sizeof(*args);
111 return 0; 110 return 0;
112 } 111 }
113 112
114 if (mp->mnt_flag & MNT_UPDATE) { 113 if (mp->mnt_flag & MNT_UPDATE) {
115 /* XXX: There is no support yet to update file system 114 /* XXX: There is no support yet to update file system
116 * settings. Should be added. */ 115 * settings. Should be added. */
117 116
118 return EOPNOTSUPP; 117 return EOPNOTSUPP;
119 } 118 }
120 119
121 if (args->ta_version != TMPFS_ARGS_VERSION) 120 if (args->ta_version != TMPFS_ARGS_VERSION)
122 return EINVAL; 121 return EINVAL;
123 122
124 /* Do not allow mounts if we do not have enough memory to preserve 123 /* Do not allow mounts if we do not have enough memory to preserve
125 * the minimum reserved pages. */ 124 * the minimum reserved pages. */
126 if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED) 125 if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED)
127 return EINVAL; 126 return EINVAL;
128 127
129 /* Get the maximum number of memory pages this file system is 128 /* Get the memory usage limit for this file-system. */
130 * allowed to use, based on the maximum size the user passed in 129 if (args->ta_size_max < PAGE_SIZE) {
131 * the mount structure. A value of zero is treated as if the 130 memlimit = UINT64_MAX;
132 * maximum available space was requested. */ 131 } else {
133 if (args->ta_size_max < PAGE_SIZE || args->ta_size_max >= SIZE_MAX) 132 memlimit = args->ta_size_max;
134 pages = SIZE_MAX; 133 }
135 else 134 KASSERT(memlimit > 0);
136 pages = args->ta_size_max / PAGE_SIZE + 135
137 (args->ta_size_max % PAGE_SIZE == 0 ? 0 : 1); 136 if (args->ta_nodes_max <= 3) {
138 if (pages > INT_MAX) 137 nodes = 3 + (memlimit / 1024);
139 pages = INT_MAX; 138 } else {
140 KASSERT(pages > 0); 
141 
142 if (args->ta_nodes_max <= 3) 
143 nodes = 3 + pages * PAGE_SIZE / 1024; 
144 else 
145 nodes = args->ta_nodes_max; 139 nodes = args->ta_nodes_max;
146 if (nodes > INT_MAX) 140 }
147 nodes = INT_MAX; 141 nodes = MIN(nodes, INT_MAX);
148 KASSERT(nodes >= 3); 142 KASSERT(nodes >= 3);
149 143
150 /* Allocate the tmpfs mount structure and fill it. */ 144 /* Allocate the tmpfs mount structure and fill it. */
151 tmp = kmem_alloc(sizeof(struct tmpfs_mount), KM_SLEEP); 145 tmp = kmem_alloc(sizeof(struct tmpfs_mount), KM_SLEEP);
152 if (tmp == NULL) 146 if (tmp == NULL)
153 return ENOMEM; 147 return ENOMEM;
154 148
155 tmp->tm_nodes_max = nodes; 149 tmp->tm_nodes_max = nodes;
156 tmp->tm_nodes_cnt = 0; 150 tmp->tm_nodes_cnt = 0;
157 LIST_INIT(&tmp->tm_nodes); 151 LIST_INIT(&tmp->tm_nodes);
158 152
159 mutex_init(&tmp->tm_lock, MUTEX_DEFAULT, IPL_NONE); 153 mutex_init(&tmp->tm_lock, MUTEX_DEFAULT, IPL_NONE);
160 154 tmpfs_mntmem_init(tmp, memlimit);
161 tmp->tm_pages_max = pages; 
162 tmp->tm_pages_used = 0; 
163 tmpfs_pool_init(&tmp->tm_dirent_pool, sizeof(struct tmpfs_dirent), 
164 "dirent", tmp); 
165 tmpfs_pool_init(&tmp->tm_node_pool, sizeof(struct tmpfs_node), 
166 "node", tmp); 
167 tmpfs_str_pool_init(&tmp->tm_str_pool, tmp); 
168 155
169 /* Allocate the root node. */ 156 /* Allocate the root node. */
170 error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid, 157 error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid,
171 args->ta_root_gid, args->ta_root_mode & ALLPERMS, NULL, NULL, 158 args->ta_root_gid, args->ta_root_mode & ALLPERMS, NULL, NULL,
172 VNOVAL, &root); 159 VNOVAL, &root);
173 KASSERT(error == 0 && root != NULL); 160 KASSERT(error == 0 && root != NULL);
174 root->tn_links++; 161 root->tn_links++;
175 tmp->tm_root = root; 162 tmp->tm_root = root;
176 163
177 mp->mnt_data = tmp; 164 mp->mnt_data = tmp;
178 mp->mnt_flag |= MNT_LOCAL; 165 mp->mnt_flag |= MNT_LOCAL;
179 mp->mnt_stat.f_namemax = MAXNAMLEN; 166 mp->mnt_stat.f_namemax = MAXNAMLEN;
180 mp->mnt_fs_bshift = PAGE_SHIFT; 167 mp->mnt_fs_bshift = PAGE_SHIFT;
181 mp->mnt_dev_bshift = DEV_BSHIFT; 168 mp->mnt_dev_bshift = DEV_BSHIFT;
182 mp->mnt_iflag |= IMNT_MPSAFE; 169 mp->mnt_iflag |= IMNT_MPSAFE;
183 vfs_getnewfsid(mp); 170 vfs_getnewfsid(mp);
184 171
185 return set_statvfs_info(path, UIO_USERSPACE, "tmpfs", UIO_SYSSPACE, 172 return set_statvfs_info(path, UIO_USERSPACE, "tmpfs", UIO_SYSSPACE,
186 mp->mnt_op->vfs_name, mp, l); 173 mp->mnt_op->vfs_name, mp, curlwp);
187} 174}
188 175
189/* --------------------------------------------------------------------- */ 176/* --------------------------------------------------------------------- */
190 177
191static int 178static int
192tmpfs_start(struct mount *mp, int flags) 179tmpfs_start(struct mount *mp, int flags)
193{ 180{
194 181
195 return 0; 182 return 0;
196} 183}
197 184
198/* --------------------------------------------------------------------- */ 185/* --------------------------------------------------------------------- */
199 186
@@ -235,33 +222,28 @@ tmpfs_unmount(struct mount *mp, int mntf @@ -235,33 +222,28 @@ tmpfs_unmount(struct mount *mp, int mntf
235 222
236 nde = TAILQ_NEXT(de, td_entries); 223 nde = TAILQ_NEXT(de, td_entries);
237 tmpfs_free_dirent(tmp, de, false); 224 tmpfs_free_dirent(tmp, de, false);
238 de = nde; 225 de = nde;
239 node->tn_size -= sizeof(struct tmpfs_dirent); 226 node->tn_size -= sizeof(struct tmpfs_dirent);
240 } 227 }
241 } 228 }
242 229
243 next = LIST_NEXT(node, tn_entries); 230 next = LIST_NEXT(node, tn_entries);
244 tmpfs_free_node(tmp, node); 231 tmpfs_free_node(tmp, node);
245 node = next; 232 node = next;
246 } 233 }
247 234
248 tmpfs_pool_destroy(&tmp->tm_dirent_pool); 
249 tmpfs_pool_destroy(&tmp->tm_node_pool); 
250 tmpfs_str_pool_destroy(&tmp->tm_str_pool); 
251 
252 KASSERT(tmp->tm_pages_used == 0); 
253 
254 /* Throw away the tmpfs_mount structure. */ 235 /* Throw away the tmpfs_mount structure. */
 236 tmpfs_mntmem_destroy(tmp);
255 mutex_destroy(&tmp->tm_lock); 237 mutex_destroy(&tmp->tm_lock);
256 kmem_free(tmp, sizeof(*tmp)); 238 kmem_free(tmp, sizeof(*tmp));
257 mp->mnt_data = NULL; 239 mp->mnt_data = NULL;
258 240
259 return 0; 241 return 0;
260} 242}
261 243
262/* --------------------------------------------------------------------- */ 244/* --------------------------------------------------------------------- */
263 245
264static int 246static int
265tmpfs_root(struct mount *mp, struct vnode **vpp) 247tmpfs_root(struct mount *mp, struct vnode **vpp)
266{ 248{
267 249
@@ -330,43 +312,42 @@ tmpfs_vptofh(struct vnode *vp, struct fi @@ -330,43 +312,42 @@ tmpfs_vptofh(struct vnode *vp, struct fi
330 node = VP_TO_TMPFS_NODE(vp); 312 node = VP_TO_TMPFS_NODE(vp);
331 313
332 memset(&tfh, 0, sizeof(tfh)); 314 memset(&tfh, 0, sizeof(tfh));
333 tfh.tf_len = sizeof(struct tmpfs_fid); 315 tfh.tf_len = sizeof(struct tmpfs_fid);
334 tfh.tf_gen = node->tn_gen; 316 tfh.tf_gen = node->tn_gen;
335 tfh.tf_id = node->tn_id; 317 tfh.tf_id = node->tn_id;
336 memcpy(fhp, &tfh, sizeof(tfh)); 318 memcpy(fhp, &tfh, sizeof(tfh));
337 319
338 return 0; 320 return 0;
339} 321}
340 322
341/* --------------------------------------------------------------------- */ 323/* --------------------------------------------------------------------- */
342 324
343/* ARGSUSED2 */ 
344static int 325static int
345tmpfs_statvfs(struct mount *mp, struct statvfs *sbp) 326tmpfs_statvfs(struct mount *mp, struct statvfs *sbp)
346{ 327{
347 fsfilcnt_t freenodes; 328 fsfilcnt_t freenodes;
348 struct tmpfs_mount *tmp; 329 struct tmpfs_mount *tmp;
349 330
350 tmp = VFS_TO_TMPFS(mp); 331 tmp = VFS_TO_TMPFS(mp);
351 332
352 sbp->f_iosize = sbp->f_frsize = sbp->f_bsize = PAGE_SIZE; 333 sbp->f_iosize = sbp->f_frsize = sbp->f_bsize = PAGE_SIZE;
353 334
354 sbp->f_blocks = TMPFS_PAGES_MAX(tmp); 335 sbp->f_blocks = (tmpfs_bytes_max(tmp) >> PAGE_SHIFT);
355 sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp); 336 sbp->f_bavail = sbp->f_bfree = tmpfs_pages_avail(tmp);
356 sbp->f_bresvd = 0; 337 sbp->f_bresvd = 0;
357 338
358 freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_cnt, 339 freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_cnt,
359 TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node)); 340 tmpfs_pages_avail(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
360 341
361 sbp->f_files = tmp->tm_nodes_cnt + freenodes; 342 sbp->f_files = tmp->tm_nodes_cnt + freenodes;
362 sbp->f_favail = sbp->f_ffree = freenodes; 343 sbp->f_favail = sbp->f_ffree = freenodes;
363 sbp->f_fresvd = 0; 344 sbp->f_fresvd = 0;
364 345
365 copy_statvfs_info(sbp, mp); 346 copy_statvfs_info(sbp, mp);
366 347
367 return 0; 348 return 0;
368} 349}
369 350
370/* --------------------------------------------------------------------- */ 351/* --------------------------------------------------------------------- */
371 352
372/* ARGSUSED0 */ 353/* ARGSUSED0 */

cvs diff -r1.69 -r1.70 src/sys/fs/tmpfs/tmpfs_vnops.c (expand / switch to unified diff)

--- src/sys/fs/tmpfs/tmpfs_vnops.c 2010/04/23 15:38:47 1.69
+++ src/sys/fs/tmpfs/tmpfs_vnops.c 2010/06/22 18:32:08 1.70
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: tmpfs_vnops.c,v 1.69 2010/04/23 15:38:47 pooka Exp $ */ 1/* $NetBSD: tmpfs_vnops.c,v 1.70 2010/06/22 18:32:08 rmind Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. 4 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 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 8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program. 9 * 2005 program.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -25,27 +25,27 @@ @@ -25,27 +25,27 @@
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33/* 33/*
34 * tmpfs vnode interface. 34 * tmpfs vnode interface.
35 */ 35 */
36 36
37#include <sys/cdefs.h> 37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.69 2010/04/23 15:38:47 pooka Exp $"); 38__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.70 2010/06/22 18:32:08 rmind Exp $");
39 39
40#include <sys/param.h> 40#include <sys/param.h>
41#include <sys/dirent.h> 41#include <sys/dirent.h>
42#include <sys/fcntl.h> 42#include <sys/fcntl.h>
43#include <sys/event.h> 43#include <sys/event.h>
44#include <sys/malloc.h> 44#include <sys/malloc.h>
45#include <sys/namei.h> 45#include <sys/namei.h>
46#include <sys/proc.h> 46#include <sys/proc.h>
47#include <sys/stat.h> 47#include <sys/stat.h>
48#include <sys/uio.h> 48#include <sys/uio.h>
49#include <sys/unistd.h> 49#include <sys/unistd.h>
50#include <sys/vnode.h> 50#include <sys/vnode.h>
51#include <sys/lockf.h> 51#include <sys/lockf.h>
@@ -851,26 +851,36 @@ tmpfs_rename(void *v) @@ -851,26 +851,36 @@ tmpfs_rename(void *v)
851 } 851 }
852 852
853 fnode = VP_TO_TMPFS_NODE(fvp); 853 fnode = VP_TO_TMPFS_NODE(fvp);
854 fdnode = VP_TO_TMPFS_DIR(fdvp); 854 fdnode = VP_TO_TMPFS_DIR(fdvp);
855 tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); 855 tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
856 tdnode = VP_TO_TMPFS_DIR(tdvp); 856 tdnode = VP_TO_TMPFS_DIR(tdvp);
857 tmp = VFS_TO_TMPFS(tdvp->v_mount); 857 tmp = VFS_TO_TMPFS(tdvp->v_mount);
858 858
859 if (fdvp == tvp) { 859 if (fdvp == tvp) {
860 error = 0; 860 error = 0;
861 goto out_unlocked; 861 goto out_unlocked;
862 } 862 }
863 863
 864 /* Allocate memory, if necessary, for a new name. */
 865 namelen = tcnp->cn_namelen;
 866 if (tmpfs_strname_neqlen(fcnp, tcnp)) {
 867 newname = tmpfs_strname_alloc(tmp, namelen);
 868 if (newname == NULL) {
 869 error = ENOSPC;
 870 goto out_unlocked;
 871 }
 872 }
 873
864 /* If we need to move the directory between entries, lock the 874 /* If we need to move the directory between entries, lock the
865 * source so that we can safely operate on it. */ 875 * source so that we can safely operate on it. */
866 876
867 /* XXX: this is a potential locking order violation! */ 877 /* XXX: this is a potential locking order violation! */
868 if (fdnode != tdnode) { 878 if (fdnode != tdnode) {
869 vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); 879 vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
870 } 880 }
871 881
872 /* 882 /*
873 * If the node we were renaming has scarpered, just give up. 883 * If the node we were renaming has scarpered, just give up.
874 */ 884 */
875 de = tmpfs_dir_lookup(fdnode, fcnp); 885 de = tmpfs_dir_lookup(fdnode, fcnp);
876 if (de == NULL || de->td_node != fnode) { 886 if (de == NULL || de->td_node != fnode) {
@@ -900,38 +910,26 @@ tmpfs_rename(void *v) @@ -900,38 +910,26 @@ tmpfs_rename(void *v)
900 } 910 }
901 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) { 911 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
902 error = ENOTDIR; 912 error = ENOTDIR;
903 goto out; 913 goto out;
904 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) { 914 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
905 error = EISDIR; 915 error = EISDIR;
906 goto out; 916 goto out;
907 } else { 917 } else {
908 KASSERT(fnode->tn_type != VDIR && 918 KASSERT(fnode->tn_type != VDIR &&
909 tnode->tn_type != VDIR); 919 tnode->tn_type != VDIR);
910 } 920 }
911 } 921 }
912 922
913 /* Ensure that we have enough memory to hold the new name, if it 
914 * has to be changed. */ 
915 namelen = tcnp->cn_namelen; 
916 if (fcnp->cn_namelen != tcnp->cn_namelen || 
917 memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { 
918 newname = tmpfs_str_pool_get(&tmp->tm_str_pool, namelen, 0); 
919 if (newname == NULL) { 
920 error = ENOSPC; 
921 goto out; 
922 } 
923 } 
924 
925 /* If the node is being moved to another directory, we have to do 923 /* If the node is being moved to another directory, we have to do
926 * the move. */ 924 * the move. */
927 if (fdnode != tdnode) { 925 if (fdnode != tdnode) {
928 /* In case we are moving a directory, we have to adjust its 926 /* In case we are moving a directory, we have to adjust its
929 * parent to point to the new parent. */ 927 * parent to point to the new parent. */
930 if (de->td_node->tn_type == VDIR) { 928 if (de->td_node->tn_type == VDIR) {
931 struct tmpfs_node *n; 929 struct tmpfs_node *n;
932 930
933 /* Ensure the target directory is not a child of the 931 /* Ensure the target directory is not a child of the
934 * directory being moved. Otherwise, we'd end up 932 * directory being moved. Otherwise, we'd end up
935 * with stale nodes. */ 933 * with stale nodes. */
936 n = tdnode; 934 n = tdnode;
937 while (n != n->tn_spec.tn_dir.tn_parent) { 935 while (n != n->tn_spec.tn_dir.tn_parent) {
@@ -979,28 +977,27 @@ tmpfs_rename(void *v) @@ -979,28 +977,27 @@ tmpfs_rename(void *v)
979 977
980 /* Free the directory entry we just deleted. Note that the 978 /* Free the directory entry we just deleted. Note that the
981 * node referred by it will not be removed until the vnode is 979 * node referred by it will not be removed until the vnode is
982 * really reclaimed. */ 980 * really reclaimed. */
983 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de2, true); 981 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de2, true);
984 } 982 }
985 983
986 /* If the name has changed, we need to make it effective by changing 984 /* If the name has changed, we need to make it effective by changing
987 * it in the directory entry. */ 985 * it in the directory entry. */
988 if (newname != NULL) { 986 if (newname != NULL) {
989 KASSERT(tcnp->cn_namelen < MAXNAMLEN); 987 KASSERT(tcnp->cn_namelen < MAXNAMLEN);
990 KASSERT(tcnp->cn_namelen < 0xffff); 988 KASSERT(tcnp->cn_namelen < 0xffff);
991 989
992 tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, 990 tmpfs_strname_free(tmp, de->td_name, de->td_namelen);
993 de->td_namelen); 
994 de->td_namelen = (uint16_t)namelen; 991 de->td_namelen = (uint16_t)namelen;
995 memcpy(newname, tcnp->cn_nameptr, namelen); 992 memcpy(newname, tcnp->cn_nameptr, namelen);
996 de->td_name = newname; 993 de->td_name = newname;
997 newname = NULL; 994 newname = NULL;
998 995
999 fnode->tn_status |= TMPFS_NODE_CHANGED; 996 fnode->tn_status |= TMPFS_NODE_CHANGED;
1000 tdnode->tn_status |= TMPFS_NODE_MODIFIED; 997 tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1001 } 998 }
1002 out_ok: 999 out_ok:
1003 /* Notify listeners of tdvp about the change in the directory (either 1000 /* Notify listeners of tdvp about the change in the directory (either
1004 * because a new entry was added or because one was removed) and 1001 * because a new entry was added or because one was removed) and
1005 * listeners of fvp about the rename. */ 1002 * listeners of fvp about the rename. */
1006 VN_KNOTE(tdvp, NOTE_WRITE); 1003 VN_KNOTE(tdvp, NOTE_WRITE);
@@ -1015,29 +1012,29 @@ tmpfs_rename(void *v) @@ -1015,29 +1012,29 @@ tmpfs_rename(void *v)
1015 out_unlocked: 1012 out_unlocked:
1016 /* Release target nodes. */ 1013 /* Release target nodes. */
1017 if (tdvp == tvp) 1014 if (tdvp == tvp)
1018 vrele(tdvp); 1015 vrele(tdvp);
1019 else 1016 else
1020 vput(tdvp); 1017 vput(tdvp);
1021 if (tvp != NULL) 1018 if (tvp != NULL)
1022 vput(tvp); 1019 vput(tvp);
1023 1020
1024 /* Release source nodes. */ 1021 /* Release source nodes. */
1025 vrele(fdvp); 1022 vrele(fdvp);
1026 vrele(fvp); 1023 vrele(fvp);
1027 1024
1028 if (newname != NULL) 1025 if (newname != NULL) {
1029 tmpfs_str_pool_put(&tmp->tm_str_pool, newname, namelen); 1026 tmpfs_strname_free(tmp, newname, namelen);
1030 1027 }
1031 return error; 1028 return error;
1032} 1029}
1033 1030
1034/* --------------------------------------------------------------------- */ 1031/* --------------------------------------------------------------------- */
1035 1032
1036int 1033int
1037tmpfs_mkdir(void *v) 1034tmpfs_mkdir(void *v)
1038{ 1035{
1039 struct vnode *dvp = ((struct vop_mkdir_args *)v)->a_dvp; 1036 struct vnode *dvp = ((struct vop_mkdir_args *)v)->a_dvp;
1040 struct vnode **vpp = ((struct vop_mkdir_args *)v)->a_vpp; 1037 struct vnode **vpp = ((struct vop_mkdir_args *)v)->a_vpp;
1041 struct componentname *cnp = ((struct vop_mkdir_args *)v)->a_cnp; 1038 struct componentname *cnp = ((struct vop_mkdir_args *)v)->a_cnp;
1042 struct vattr *vap = ((struct vop_mkdir_args *)v)->a_vap; 1039 struct vattr *vap = ((struct vop_mkdir_args *)v)->a_vap;
1043 1040

cvs diff -r1.1 -r1.2 src/sys/modules/tmpfs/Makefile (expand / switch to unified diff)

--- src/sys/modules/tmpfs/Makefile 2008/06/28 16:11:36 1.1
+++ src/sys/modules/tmpfs/Makefile 2010/06/22 18:32:08 1.2
@@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
1# $NetBSD: Makefile,v 1.1 2008/06/28 16:11:36 rumble Exp $ 1# $NetBSD: Makefile,v 1.2 2010/06/22 18:32:08 rmind Exp $
2 2
3.include "../Makefile.inc" 3.include "../Makefile.inc"
4 4
5.PATH: ${S}/fs/tmpfs 5.PATH: ${S}/fs/tmpfs
6 6
7KMOD= tmpfs 7KMOD= tmpfs
8SRCS= tmpfs_fifoops.c tmpfs_pool.c tmpfs_specops.c tmpfs_subr.c \ 8SRCS= tmpfs_fifoops.c tmpfs_mem.c tmpfs_specops.c tmpfs_subr.c \
9 tmpfs_vfsops.c tmpfs_vnops.c 9 tmpfs_vfsops.c tmpfs_vnops.c
10 10
11.include <bsd.kmodule.mk> 11.include <bsd.kmodule.mk>

cvs diff -r1.3 -r1.4 src/sys/rump/fs/lib/libtmpfs/Makefile (expand / switch to unified diff)

--- src/sys/rump/fs/lib/libtmpfs/Makefile 2008/07/29 13:17:43 1.3
+++ src/sys/rump/fs/lib/libtmpfs/Makefile 2010/06/22 18:32:08 1.4
@@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
1# $NetBSD: Makefile,v 1.3 2008/07/29 13:17:43 pooka Exp $ 1# $NetBSD: Makefile,v 1.4 2010/06/22 18:32:08 rmind Exp $
2# 2#
3 3
4.PATH: ${.CURDIR}/../../../../fs/tmpfs 4.PATH: ${.CURDIR}/../../../../fs/tmpfs
5 5
6LIB= rumpfs_tmpfs 6LIB= rumpfs_tmpfs
7 7
8SRCS= tmpfs_fifoops.c tmpfs_specops.c tmpfs_vfsops.c tmpfs_pool.c \ 8SRCS= tmpfs_fifoops.c tmpfs_specops.c tmpfs_vfsops.c tmpfs_mem.c \
9 tmpfs_subr.c tmpfs_vnops.c 9 tmpfs_subr.c tmpfs_vnops.c
10 10
11.include <bsd.lib.mk> 11.include <bsd.lib.mk>
12.include <bsd.klinks.mk> 12.include <bsd.klinks.mk>