diff options
author | phk <phk@FreeBSD.org> | 2005-03-14 12:29:39 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2005-03-14 12:29:39 +0000 |
commit | 550b89f8bfbf1870fb5386f1adf3c242fdd3446e (patch) | |
tree | 389cb6457304ccf341950e458a813af87a6beaae /sys/fs/udf | |
parent | 5c46906245a2a84289caf32ca07bd30a5d1a7ac8 (diff) | |
download | FreeBSD-src-550b89f8bfbf1870fb5386f1adf3c242fdd3446e.zip FreeBSD-src-550b89f8bfbf1870fb5386f1adf3c242fdd3446e.tar.gz |
Use vfs_hash instead of home-rolled.
Correct locking around g_vfs_close()
Diffstat (limited to 'sys/fs/udf')
-rw-r--r-- | sys/fs/udf/udf.h | 6 | ||||
-rw-r--r-- | sys/fs/udf/udf_vfsops.c | 84 | ||||
-rw-r--r-- | sys/fs/udf/udf_vnops.c | 74 |
3 files changed, 52 insertions, 112 deletions
diff --git a/sys/fs/udf/udf.h b/sys/fs/udf/udf.h index 820a486..1437e3b 100644 --- a/sys/fs/udf/udf.h +++ b/sys/fs/udf/udf.h @@ -53,9 +53,6 @@ struct udf_mnt { uint32_t part_len; uint64_t root_id; struct long_ad root_icb; - LIST_HEAD(udf_hash_lh, udf_node) *hashtbl; - u_long hashsz; - struct mtx hash_mtx; int p_sectors; int s_table_entries; struct udf_sparing_table *s_table; @@ -130,9 +127,6 @@ udf_getid(struct long_ad *icb) } int udf_allocv(struct mount *, struct vnode **, struct thread *); -int udf_hashlookup(struct udf_mnt *, ino_t, int, struct vnode **); -int udf_hashins(struct udf_node *); -int udf_hashrem(struct udf_node *); int udf_checktag(struct desc_tag *, uint16_t); int udf_vget(struct mount *, ino_t, int, struct vnode **); diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c index 6733b78..6a9f9e7 100644 --- a/sys/fs/udf/udf_vfsops.c +++ b/sys/fs/udf/udf_vfsops.c @@ -474,9 +474,6 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { brelse(bp); bp = NULL; - mtx_init(&udfmp->hash_mtx, "udf_hash", NULL, MTX_DEF); - udfmp->hashtbl = phashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, &udfmp->hashsz); - return 0; bail: @@ -515,15 +512,16 @@ udf_unmount(struct mount *mp, int mntflags, struct thread *td) #endif } + DROP_GIANT(); + g_topology_lock(); g_vfs_close(udfmp->im_cp, td); + g_topology_unlock(); + PICKUP_GIANT(); vrele(udfmp->im_devvp); if (udfmp->s_table != NULL) FREE(udfmp->s_table, M_UDFMOUNT); - if (udfmp->hashtbl != NULL) - FREE(udfmp->hashtbl, M_UDFMOUNT); - FREE(udfmp, M_UDFMOUNT); mp->mnt_data = (qaddr_t)0; @@ -583,24 +581,52 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) struct file_entry *fe; int error, sector, size; + error = vfs_hash_get(mp, ino, flags, curthread, vpp); + if (error) + return (error); + if (*vpp != NULL) + return (0); + td = curthread; udfmp = VFSTOUDFFS(mp); - /* See if we already have this in the cache */ - if ((error = udf_hashlookup(udfmp, ino, flags, vpp)) != 0) + unode = uma_zalloc(udf_zone_node, M_WAITOK | M_ZERO); + + if ((error = udf_allocv(mp, &vp, td))) { + printf("Error from udf_allocv\n"); + uma_zfree(udf_zone_node, unode); return (error); - if (*vpp != NULL) { - return (0); } + unode->i_vnode = vp; + unode->hash_id = ino; + unode->i_devvp = udfmp->im_devvp; + unode->i_dev = udfmp->im_dev; + unode->udfmp = udfmp; + vp->v_data = unode; + /* - * Allocate memory and check the tag id's before grabbing a new - * vnode, since it's hard to roll back if there is a problem. + * Exclusively lock the vnode before adding to hash. Note, that we + * must not release nor downgrade the lock (despite flags argument + * says) till it is fully initialized. */ - unode = uma_zalloc(udf_zone_node, M_WAITOK); - if (unode == NULL) { - printf("Cannot allocate udf node\n"); - return (ENOMEM); + lockmgr(vp->v_vnlock, LK_EXCLUSIVE, (struct mtx *)0, td); + + /* + * Atomicaly (in terms of vfs_hash operations) check the hash for + * duplicate of vnode being created and add it to the hash. If a + * duplicate vnode was found, it will be vget()ed from hash for us. + */ + if ((error = vfs_hash_insert(vp, ino, flags, curthread, vpp)) != 0) { + vput(vp); + *vpp = NULL; + return (error); + } + + /* We lost the race, then throw away our vnode and return existing */ + if (*vpp != NULL) { + vput(vp); + return (0); } /* @@ -610,15 +636,18 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) devvp = udfmp->im_devvp; if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) { printf("Cannot read sector %d\n", sector); - uma_zfree(udf_zone_node, unode); + vput(vp); + brelse(bp); + *vpp = NULL; return (error); } fe = (struct file_entry *)bp->b_data; if (udf_checktag(&fe->tag, TAGID_FENTRY)) { printf("Invalid file entry!\n"); - uma_zfree(udf_zone_node, unode); + vput(vp); brelse(bp); + *vpp = NULL; return (ENOMEM); } size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad); @@ -626,31 +655,18 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) M_NOWAIT | M_ZERO); if (unode->fentry == NULL) { printf("Cannot allocate file entry block\n"); - uma_zfree(udf_zone_node, unode); + vput(vp); brelse(bp); + *vpp = NULL; return (ENOMEM); } + VREF(udfmp->im_devvp); bcopy(bp->b_data, unode->fentry, size); brelse(bp); bp = NULL; - if ((error = udf_allocv(mp, &vp, td))) { - printf("Error from udf_allocv\n"); - uma_zfree(udf_zone_node, unode); - return (error); - } - - unode->i_vnode = vp; - unode->hash_id = ino; - unode->i_devvp = udfmp->im_devvp; - unode->i_dev = udfmp->im_dev; - unode->udfmp = udfmp; - vp->v_data = unode; - VREF(udfmp->im_devvp); - udf_hashins(unode); - switch (unode->fentry->icbtag.file_type) { default: vp->v_type = VBAD; diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index d702629..7a99b1e 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -36,6 +36,7 @@ #include <sys/malloc.h> #include <sys/stat.h> #include <sys/bio.h> +#include <sys/conf.h> #include <sys/buf.h> #include <sys/iconv.h> #include <sys/mount.h> @@ -92,77 +93,6 @@ MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure"); #define UDF_INVALID_BMAP -1 -/* Look up a udf_node based on the ino_t passed in and return it's vnode */ -int -udf_hashlookup(struct udf_mnt *udfmp, ino_t id, int flags, struct vnode **vpp) -{ - struct udf_node *node; - struct udf_hash_lh *lh; - int error; - - *vpp = NULL; - -loop: - mtx_lock(&udfmp->hash_mtx); - lh = &udfmp->hashtbl[id % udfmp->hashsz]; - if (lh == NULL) - return (ENOENT); - LIST_FOREACH(node, lh, le) { - if (node->hash_id == id) { - VI_LOCK(node->i_vnode); - mtx_unlock(&udfmp->hash_mtx); - error = vget(node->i_vnode, flags | LK_INTERLOCK, - curthread); - if (error == ENOENT) - goto loop; - if (error) - return (error); - *vpp = node->i_vnode; - return (0); - } - } - - mtx_unlock(&udfmp->hash_mtx); - return (0); -} - -int -udf_hashins(struct udf_node *node) -{ - struct udf_mnt *udfmp; - struct udf_hash_lh *lh; - - udfmp = node->udfmp; - - vn_lock(node->i_vnode, LK_EXCLUSIVE | LK_RETRY, curthread); - mtx_lock(&udfmp->hash_mtx); - lh = &udfmp->hashtbl[node->hash_id % udfmp->hashsz]; - if (lh == NULL) - LIST_INIT(lh); - LIST_INSERT_HEAD(lh, node, le); - mtx_unlock(&udfmp->hash_mtx); - - return (0); -} - -int -udf_hashrem(struct udf_node *node) -{ - struct udf_mnt *udfmp; - struct udf_hash_lh *lh; - - udfmp = node->udfmp; - - mtx_lock(&udfmp->hash_mtx); - lh = &udfmp->hashtbl[node->hash_id % udfmp->hashsz]; - if (lh == NULL) - panic("hash entry is NULL, node->hash_id= %d\n", node->hash_id); - LIST_REMOVE(node, le); - mtx_unlock(&udfmp->hash_mtx); - - return (0); -} - int udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td) { @@ -1037,7 +967,7 @@ udf_reclaim(struct vop_reclaim_args *a) unode = VTON(vp); if (unode != NULL) { - udf_hashrem(unode); + vfs_hash_remove(vp); if (unode->i_devvp) { vrele(unode->i_devvp); unode->i_devvp = 0; |