diff options
author | delphij <delphij@FreeBSD.org> | 2007-07-08 15:56:12 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2007-07-08 15:56:12 +0000 |
commit | b4ff5952426a6e92dc21f676c1929eea72c2d9a4 (patch) | |
tree | 6ac0bd7afea293c01d39622b1f9361df605db31d | |
parent | 4df766d13509673472d8fac9e2b4fd393fa2a98f (diff) | |
download | FreeBSD-src-b4ff5952426a6e92dc21f676c1929eea72c2d9a4.zip FreeBSD-src-b4ff5952426a6e92dc21f676c1929eea72c2d9a4.tar.gz |
MFp4:
- Plug memory leak.
- Respect underlying vnode's properties rather than assuming that
the user want root:wheel + 0755. Useful for using tmpfs(5) for
/tmp.
- Use roundup2 and howmany macros instead of rolling our own version.
- Try to fix fsx -W -R foo case.
- Instead of blindly zeroing a page, determine whether we need a pagein
order to prevent data corruption.
- Fix several bugs reported by Coverity.
Submitted by: Mingyan Guo <guomingyan gmail com>, Howard Su, delphij
Coverity ID: CID 2550, 2551, 2552, 2557
Approved by: re (tmpfs blanket)
-rw-r--r-- | sys/fs/tmpfs/tmpfs.h | 26 | ||||
-rw-r--r-- | sys/fs/tmpfs/tmpfs_subr.c | 38 | ||||
-rw-r--r-- | sys/fs/tmpfs/tmpfs_vfsops.c | 63 | ||||
-rw-r--r-- | sys/fs/tmpfs/tmpfs_vnops.c | 23 |
4 files changed, 83 insertions, 67 deletions
diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index 34e439b..3731342 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -467,8 +467,8 @@ TMPFS_PAGES_MAX(struct tmpfs_mount *tmp) } /* Returns the available space for the given file system. */ -#define TMPFS_META_PAGES(tmp) ((tmp)->tm_nodes_inuse * (sizeof(struct tmpfs_node) \ - + sizeof(struct tmpfs_dirent))/PAGE_SIZE + 1) +#define TMPFS_META_PAGES(tmp) (howmany((tmp)->tm_nodes_inuse * (sizeof(struct tmpfs_node) \ + + sizeof(struct tmpfs_dirent)), PAGE_SIZE)) #define TMPFS_FILE_PAGES(tmp) ((tmp)->tm_pages_used) #define TMPFS_PAGES_AVAIL(tmp) (TMPFS_PAGES_MAX(tmp) > \ @@ -518,26 +518,4 @@ VP_TO_TMPFS_DIR(struct vnode *vp) return node; } -/* --------------------------------------------------------------------- - * USER AND KERNEL DEFINITIONS - * --------------------------------------------------------------------- */ - -/* - * This structure is used to communicate mount parameters between userland - * and kernel space. - */ -#define TMPFS_ARGS_VERSION 1 -struct tmpfs_args { - int ta_version; - - /* Size counters. */ - ino_t ta_nodes_max; - off_t ta_size_max; - - /* Root node attributes. */ - uid_t ta_root_uid; - gid_t ta_root_gid; - mode_t ta_root_mode; - -}; #endif /* _FS_TMPFS_TMPFS_H_ */ diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 76d2b54..b9a706d 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -312,7 +312,9 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp, loop: if (node->tn_vnode != NULL) { vp = node->tn_vnode; - vget(vp, LK_EXCLUSIVE | LK_RETRY, td); + error = vget(vp, LK_EXCLUSIVE | LK_RETRY, td); + if (error) + return error; /* * Make sure the vnode is still there after @@ -323,7 +325,6 @@ loop: goto loop; } - error = 0; goto out; } @@ -385,9 +386,17 @@ loop: } vnode_pager_setsize(vp, node->tn_size); - insmntque(vp, mp); - - error = 0; + error = insmntque(vp, mp); + if (error) { + node->tn_vnode = NULL; + if (node->tn_vpstate & TMPFS_VNODE_WANT) { + node->tn_vpstate &= ~TMPFS_VNODE_WANT; + TMPFS_NODE_UNLOCK(node); + wakeup((caddr_t) &node->tn_vpstate); + } else + TMPFS_NODE_UNLOCK(node); + return error; + } node->tn_vnode = vp; unlock: @@ -850,32 +859,33 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize) node->tn_size = newsize; vnode_pager_setsize(vp, newsize); if (newsize < oldsize) { - size_t zerolen = MIN(round_page(newsize), node->tn_size) - newsize; - struct vm_object *uobj = node->tn_reg.tn_aobj; + size_t zerolen = round_page(newsize) - newsize; + vm_object_t uobj = node->tn_reg.tn_aobj; vm_page_t m; /* * free "backing store" */ - + VM_OBJECT_LOCK(uobj); if (newpages < oldpages) { - VM_OBJECT_LOCK(uobj); swap_pager_freespace(uobj, newpages, oldpages - newpages); - VM_OBJECT_UNLOCK(uobj); + vm_object_page_remove(uobj, + OFF_TO_IDX(newsize + PAGE_MASK), 0, FALSE); } /* * zero out the truncated part of the last page. */ - if (zerolen > 0) { + if (zerolen > 0) { m = vm_page_grab(uobj, OFF_TO_IDX(newsize), VM_ALLOC_NORMAL | VM_ALLOC_RETRY); pmap_zero_page_area(m, PAGE_SIZE - zerolen, zerolen); vm_page_wakeup(m); - } + } + VM_OBJECT_UNLOCK(uobj); } @@ -1226,10 +1236,6 @@ void tmpfs_update(struct vnode *vp) { - struct tmpfs_node *node; - - node = VP_TO_TMPFS_NODE(vp); - tmpfs_itimes(vp, NULL, NULL); } diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c index 0546cbf..5ee548b 100644 --- a/sys/fs/tmpfs/tmpfs_vfsops.c +++ b/sys/fs/tmpfs/tmpfs_vfsops.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/kernel.h> @@ -151,6 +152,8 @@ tmpfs_node_ctor(void *mem, int size, void *arg, int flags) TMPFS_LOCK(tmp); node->tn_id = tmp->tm_nodes_last++; TMPFS_UNLOCK(tmp); + if (node->tn_id == INT_MAX) + panic("all avariable id is used."); node->tn_gen = arc4random(); } else { node->tn_gen++; @@ -195,14 +198,23 @@ tmpfs_node_fini(void *mem, int size) } static int -tmpfs_mount(struct mount *mp, struct thread *l) +tmpfs_mount(struct mount *mp, struct thread *td) { - struct tmpfs_args args; struct tmpfs_mount *tmp; struct tmpfs_node *root; size_t pages, mem_size; ino_t nodes; int error; + /* Size counters. */ + ino_t nodes_max; + off_t size_max; + + /* Root node attributes. */ + uid_t root_uid; + gid_t root_gid; + mode_t root_mode; + + struct vattr va; if (vfs_filteropt(mp->mnt_optnew, tmpfs_opts)) return (EINVAL); @@ -214,19 +226,28 @@ tmpfs_mount(struct mount *mp, struct thread *l) return EOPNOTSUPP; } - if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &args.ta_root_gid) != 1) - args.ta_root_gid = 0; - if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &args.ta_root_uid) != 1) - args.ta_root_uid = 0; - if (vfs_scanopt(mp->mnt_optnew, "mode", "%o", &args.ta_root_mode) != 1) - args.ta_root_mode = TMPFS_DEFAULT_ROOT_MODE; - if(vfs_scanopt(mp->mnt_optnew, "inodes", "%d", &args.ta_nodes_max) != 1) - args.ta_nodes_max = 0; + vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY, td); + error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred, td); + VOP_UNLOCK(mp->mnt_vnodecovered, 0, td); + if (error) + return (error); + + if (mp->mnt_cred->cr_ruid != 0 || + vfs_scanopt(mp->mnt_optnew, "gid", "%d", &root_gid) != 1) + root_gid = va.va_gid; + if (mp->mnt_cred->cr_ruid != 0 || + vfs_scanopt(mp->mnt_optnew, "uid", "%d", &root_uid) != 1) + root_uid = va.va_uid; + if (mp->mnt_cred->cr_ruid != 0 || + vfs_scanopt(mp->mnt_optnew, "mode", "%o", &root_mode) != 1) + root_mode = va.va_mode; + if(vfs_scanopt(mp->mnt_optnew, "inodes", "%d", &nodes_max) != 1) + nodes_max = 0; if(vfs_scanopt(mp->mnt_optnew, "size", - "%qu", &args.ta_size_max) != 1) - args.ta_size_max = 0; + "%qu", &size_max) != 1) + size_max = 0; /* Do not allow mounts if we do not have enough memory to preserve * the minimum reserved pages. */ @@ -239,17 +260,16 @@ tmpfs_mount(struct mount *mp, struct thread *l) * allowed to use, based on the maximum size the user passed in * the mount structure. A value of zero is treated as if the * maximum available space was requested. */ - if (args.ta_size_max < PAGE_SIZE || args.ta_size_max >= SIZE_MAX) + if (size_max < PAGE_SIZE || size_max >= SIZE_MAX) pages = SIZE_MAX; else - pages = args.ta_size_max / PAGE_SIZE + - (args.ta_size_max % PAGE_SIZE == 0 ? 0 : 1); + pages = howmany(size_max, PAGE_SIZE); MPASS(pages > 0); - if (args.ta_nodes_max <= 3) + if (nodes_max <= 3) nodes = 3 + pages * PAGE_SIZE / 1024; else - nodes = args.ta_nodes_max; + nodes = nodes_max; MPASS(nodes >= 3); /* Allocate the tmpfs mount structure and fill it. */ @@ -277,12 +297,12 @@ tmpfs_mount(struct mount *mp, struct thread *l) tmpfs_node_ctor, tmpfs_node_dtor, tmpfs_node_init, tmpfs_node_fini, UMA_ALIGN_PTR, - UMA_ZONE_NOFREE); + 0); /* Allocate the root node. */ - error = tmpfs_alloc_node(tmp, VDIR, args.ta_root_uid, - args.ta_root_gid, args.ta_root_mode & ALLPERMS, NULL, NULL, - VNOVAL, l, &root); + error = tmpfs_alloc_node(tmp, VDIR, root_uid, + root_gid, root_mode & ALLPERMS, NULL, NULL, + VNOVAL, td, &root); if (error != 0 || root == NULL) { uma_zdestroy(tmp->tm_node_pool); @@ -360,6 +380,7 @@ tmpfs_unmount(struct mount *mp, int mntflags, struct thread *l) mtx_destroy(&tmp->allnode_lock); MPASS(tmp->tm_pages_used == 0); + MPASS(tmp->tm_nodes_inuse == 0); /* Throw away the tmpfs_mount structure. */ free(mp->mnt_data, M_TMPFSMNT); diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 520fff7e..69f6e47 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -450,6 +450,7 @@ tmpfs_uio_xfer(struct tmpfs_mount *tmp, struct tmpfs_node *node, vm_page_t m; size_t len; int error = 0; + int behind = 0, ahead = 0; /* uobj - locked by caller */ @@ -468,8 +469,21 @@ tmpfs_uio_xfer(struct tmpfs_mount *tmp, struct tmpfs_node *node, len = MIN(len, (PAGE_SIZE - d)); m = vm_page_grab(uobj, idx, VM_ALLOC_WIRED | VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY); - if (uio->uio_rw == UIO_READ && m->valid != VM_PAGE_BITS_ALL) - vm_page_zero_invalid(m, TRUE); + if (m->valid != VM_PAGE_BITS_ALL){ + if (vm_pager_has_page(uobj, idx, &behind, &ahead)){ + error = vm_pager_get_pages(uobj, &m, 1, 0); + if (error == VM_PAGER_ERROR){ + printf("vm_pager_get_pages error\n"); + goto out; + } +#ifdef DIAGNOSTIC + /* XXX */ + printf("tmpfs gets page from pager\n"); +#endif + } else { + vm_page_zero_invalid(m, TRUE); + } + } VM_OBJECT_UNLOCK(uobj); sched_pin(); sf = sf_buf_alloc(m, SFB_CPUPRIVATE); @@ -488,6 +502,7 @@ tmpfs_uio_xfer(struct tmpfs_mount *tmp, struct tmpfs_node *node, vm_page_wakeup(m); vm_page_unlock_queues(); } +out: vm_object_pip_subtract(uobj, 1); VM_OBJECT_UNLOCK(uobj); return error; @@ -680,14 +695,12 @@ tmpfs_link(struct vop_link_args *v) int error; struct tmpfs_dirent *de; - struct tmpfs_node *dnode; struct tmpfs_node *node; MPASS(VOP_ISLOCKED(dvp, cnp->cn_thread)); MPASS(cnp->cn_flags & HASBUF); MPASS(dvp != vp); /* XXX When can this be false? */ - dnode = VP_TO_TMPFS_DIR(dvp); node = VP_TO_TMPFS_NODE(vp); /* XXX: Why aren't the following two tests done by the caller? */ @@ -753,7 +766,6 @@ tmpfs_rename(struct vop_rename_args *v) char *newname; int error; struct tmpfs_dirent *de; - struct tmpfs_mount *tmp; struct tmpfs_node *fdnode; struct tmpfs_node *fnode; struct tmpfs_node *tdnode; @@ -775,7 +787,6 @@ tmpfs_rename(struct vop_rename_args *v) goto out; } - tmp = VFS_TO_TMPFS(tdvp->v_mount); tdnode = VP_TO_TMPFS_DIR(tdvp); /* If source and target are the same file, there is nothing to do. */ |