summaryrefslogtreecommitdiff
path: root/sys/fs/udf/udf_vfsops.c
diff options
context:
space:
mode:
authorPoul-Henning Kamp <phk@FreeBSD.org>2005-03-14 12:29:39 +0000
committerPoul-Henning Kamp <phk@FreeBSD.org>2005-03-14 12:29:39 +0000
commit4e94fafc4fb53b5bbdda750a2d85cb058a6b8de2 (patch)
tree389cb6457304ccf341950e458a813af87a6beaae /sys/fs/udf/udf_vfsops.c
parenta30fc63b19b3a9508e13660f06a9a825c8e5b548 (diff)
Notes
Diffstat (limited to 'sys/fs/udf/udf_vfsops.c')
-rw-r--r--sys/fs/udf/udf_vfsops.c84
1 files changed, 50 insertions, 34 deletions
diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c
index 6733b7815886..6a9f9e71c6dd 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;