1/*
2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
25 */
26/*
27 * Copyright (c) 1982, 1986, 1989, 1991, 1993
28 *	The Regents of the University of California.  All rights reserved.
29 *
30 * The NEXTSTEP Software License Agreement specifies the terms
31 * and conditions for redistribution.
32 *
33 *	@(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/mount.h>
39#include <sys/ucred.h>
40#include <sys/vnode.h>
41#include <sys/malloc.h>
42#include <sys/proc.h>
43
44#include "webdav.h"
45#include "webdav_utils.h"
46
47/*****************************************************************************/
48
49/*
50 * Structures associated with webdav noade cacheing.
51 */
52LIST_HEAD(webdav_hashhead, webdavnode) *webdav_hashtbl = NULL;
53u_long webdavhash;  /* size of hash table - 1 */
54
55lck_mtx_t *webdav_node_hash_mutex;	/* protects the hash table */
56static lck_grp_t *webdav_node_hash_lck_grp;
57
58/*
59 * The keys are the mount address and the fileid. The mount address will prevent
60 * collisions between mounts and the fileid is unique on a mount.
61 */
62#define WEBDAVNODEHASH(mp, fileid) (&webdav_hashtbl[((u_long)(mp) + (u_long)(fileid)) & webdavhash])
63
64/*****************************************************************************/
65
66/*
67 * Initialize webdav hash table.
68 */
69__private_extern__
70void webdav_hashinit(void)
71{
72	webdav_hashtbl = hashinit(desiredvnodes, M_TEMP, &webdavhash);
73	webdav_node_hash_lck_grp = lck_grp_alloc_init("webdav_node_hash", LCK_GRP_ATTR_NULL);
74	webdav_node_hash_mutex = lck_mtx_alloc_init(webdav_node_hash_lck_grp, LCK_ATTR_NULL);
75}
76
77/*****************************************************************************/
78
79/*
80 * Free webdav hash table.
81 */
82__private_extern__
83void webdav_hashdestroy(void)
84{
85	if (webdav_hashtbl != NULL)
86	{
87		FREE(webdav_hashtbl, M_TEMP);
88	}
89
90	lck_mtx_free(webdav_node_hash_mutex, webdav_node_hash_lck_grp);
91	lck_grp_free(webdav_node_hash_lck_grp);
92}
93
94/*****************************************************************************/
95
96/*
97 * Use the mp/fileid pair to find the webdavnode.
98 * If found but busy, then wait for it.
99 *
100 *
101 */
102 __private_extern__
103struct webdavnode *webdav_hashget(struct mount *mp, webdav_ino_t fileid, struct webdavnode *pt_new, uint32_t *inserted)
104{
105	struct webdavnode *pt, *pt_found;
106	struct webdav_hashhead *nhp;
107	vnode_t vp;
108	uint32_t vid;
109
110	vp = NULLVP;
111	pt_found = NULL;
112	nhp = WEBDAVNODEHASH(mp, fileid);
113
114lockAndLoop:
115	lck_mtx_lock(webdav_node_hash_mutex);
116loop:
117	for (pt = nhp->lh_first; pt != NULL; pt = pt->pt_hash.le_next)
118	{
119		if ( (mp != pt->pt_mountp) || (pt->pt_fileid != fileid) )
120			continue;
121
122		/* found a match */
123		if (ISSET(pt->pt_status, WEBDAV_INIT))
124		{
125			/*
126			 * The webdavnode is being initialized.
127			 * Wait for initialization to complete and then restart the search.
128			 */
129			SET(pt->pt_status, WEBDAV_WAITINIT);
130			msleep(pt, webdav_node_hash_mutex, PINOD, "webdav_hashget", NULL);
131			goto loop;
132		}
133
134		vp = WEBDAVTOV(pt);
135		vid = vnode_vid(vp);
136		lck_mtx_unlock(webdav_node_hash_mutex);
137
138		if (vnode_getwithvid(vp, vid))
139		{
140			/* vnode is being reclaimed, or has changed identity, so try again */
141			goto lockAndLoop;
142		}
143
144		/* found what we needed */
145		webdav_lock(pt, WEBDAV_EXCLUSIVE_LOCK);
146		pt->pt_lastvop = webdav_hashget;
147		pt_found = pt;
148		*inserted = 0;
149		return (pt_found);
150	}
151
152	/* Not found in the hash */
153	if (pt_new != NULL)
154	{
155		/* insert the new node */
156		pt_new->pt_status |= WEBDAV_ONHASHLIST;
157		LIST_INSERT_HEAD(nhp, pt_new, pt_hash);
158		webdav_lock(pt_new, WEBDAV_EXCLUSIVE_LOCK);
159		pt_new->pt_lastvop = webdav_hashget;
160		*inserted = 1;
161	}
162	else
163		*inserted = 0;
164	lck_mtx_unlock(webdav_node_hash_mutex);
165
166	return (pt_new);
167}
168
169
170/*****************************************************************************/
171
172/*
173 * Insert the inode into the hash table
174 */
175__private_extern__
176void webdav_hashins(pt)
177	struct webdavnode *pt;
178{
179	lck_mtx_lock(webdav_node_hash_mutex);
180	/*	put it on the appropriate hash list */
181	LIST_INSERT_HEAD(WEBDAVNODEHASH(pt->pt_mountp, pt->pt_fileid), pt, pt_hash);
182	pt->pt_status |= WEBDAV_ONHASHLIST;
183	lck_mtx_unlock(webdav_node_hash_mutex);
184}
185
186/*****************************************************************************/
187
188/*
189 * Remove the inode from the hash table.
190 */
191__private_extern__
192void webdav_hashrem(pt)
193	struct webdavnode *pt;
194{
195	lck_mtx_lock(webdav_node_hash_mutex);
196	if (pt->pt_status & WEBDAV_ONHASHLIST)
197	{
198		LIST_REMOVE(pt, pt_hash);
199		pt->pt_status &= ~WEBDAV_ONHASHLIST;
200	}
201	lck_mtx_unlock(webdav_node_hash_mutex);
202}
203
204/*****************************************************************************/
205