1 /*
2  * Copyright (c) 2000-2001, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: smbfs_node.h,v 1.31.52.1 2005/05/27 02:35:28 lindak Exp $
33  */
34 
35 /*
36  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 #ifndef _FS_SMBFS_NODE_H_
41 #define	_FS_SMBFS_NODE_H_
42 
43 /*
44  * Much code copied into here from Sun NFS.
45  * Compare with nfs_clnt.h
46  */
47 
48 #include <sys/avl.h>
49 #include <sys/list.h>
50 
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54 
55 /*
56  * These are the attributes we can get from the server via
57  * SMB commands such as TRANS2_QUERY_FILE_INFORMATION
58  * with info level SMB_QFILEINFO_ALL_INFO, and directory
59  * FindFirst/FindNext info. levels FIND_DIRECTORY_INFO
60  * and FIND_BOTH_DIRECTORY_INFO, etc.
61  *
62  * Values in this struct are always native endian,
63  * and times are converted converted to Unix form.
64  * Note: zero in any of the times means "unknown".
65  *
66  * XXX: Later, move this to nsmb
67  */
68 typedef struct smbfattr {
69 	timespec_t	fa_createtime;	/* Note, != ctime */
70 	timespec_t	fa_atime;	/* these 3 are like unix */
71 	timespec_t	fa_mtime;
72 	timespec_t	fa_ctime;
73 	u_offset_t	fa_size;	/* EOF position */
74 	u_offset_t	fa_allocsz;	/* Allocated size. */
75 	uint32_t	fa_attr;	/* Ext. file (DOS) attr */
76 } smbfattr_t;
77 
78 /*
79  * Cache whole directories (not yet)
80  */
81 typedef struct rddir_cache {
82 	lloff_t _cookie;	/* cookie used to find this cache entry */
83 	lloff_t _ncookie;	/* cookie used to find the next cache entry */
84 	char *entries;		/* buffer containing dirent entries */
85 	int eof;		/* EOF reached after this request */
86 	int entlen;		/* size of dirent entries in buf */
87 	int buflen;		/* size of the buffer used to store entries */
88 	int flags;		/* control flags, see below */
89 	kcondvar_t cv;		/* cv for blocking */
90 	int error;		/* error from RPC operation */
91 	kmutex_t lock;
92 	uint_t count;		/* reference count */
93 	avl_node_t tree;	/* AVL tree links */
94 } rddir_cache;
95 
96 #define	smbfs_cookie	_cookie._p._l
97 #define	smbfs_ncookie	_ncookie._p._l
98 #define	smbfs3_cookie	_cookie._f
99 #define	smbfs3_ncookie	_ncookie._f
100 
101 #define	RDDIR		0x1	/* readdir operation in progress */
102 #define	RDDIRWAIT	0x2	/* waiting on readdir in progress */
103 #define	RDDIRREQ	0x4	/* a new readdir is required */
104 #define	RDDIRCACHED	0x8	/* entry is in the cache */
105 
106 #define	HAVE_RDDIR_CACHE(rp)	(avl_numnodes(&(rp)->r_dir) > 0)
107 
108 /*
109  * A homegrown reader/writer lock implementation.  It addresses
110  * two requirements not addressed by the system primitives.  They
111  * are that the `enter" operation is optionally interruptible and
112  * that that they can be re`enter'ed by writers without deadlock.
113  */
114 typedef struct smbfs_rwlock {
115 	int count;
116 	int waiters;
117 	kthread_t *owner;
118 	kmutex_t lock;
119 	kcondvar_t cv;
120 } smbfs_rwlock_t;
121 
122 /*
123  * The format of the smbfs node header, which contains the
124  * fields used to link nodes in the AVL tree, and those
125  * fields needed by the AVL node comparison functions.
126  * It's a separate struct so we can call avl_find with
127  * this relatively small struct as a stack local.
128  *
129  * The AVL tree is mntinfo.smi_hash_avl,
130  * and its lock is mntinfo.smi_hash_lk.
131  */
132 typedef struct smbfs_node_hdr {
133 	/*
134 	 * Our linkage in the node cache AVL tree.
135 	 */
136 	avl_node_t	hdr_avl_node;
137 
138 	/*
139 	 * Identity of this node:  The full path name,
140 	 * in server form, relative to the share root.
141 	 */
142 	char		*hdr_n_rpath;
143 	int		hdr_n_rplen;
144 } smbfs_node_hdr_t;
145 
146 /*
147  * Below is the SMBFS-specific representation of a "node".
148  * This struct is a mixture of Sun NFS and Darwin code.
149  * Fields starting with "r_" came from NFS struct "rnode"
150  * and fields starting with "n_" came from Darwin, or
151  * were added during the Solaris port.  We have avoided
152  * renaming fields so we would not cause excessive
153  * changes in the code using this struct.
154  *
155  * Now using an AVL tree instead of hash lists, but kept the
156  * "hash" in some member names and functions to reduce churn.
157  * One AVL tree per mount replaces the global hash buckets.
158  *
159  * Notes carried over from the NFS code:
160  *
161  * The smbnode is the "inode" for remote files.  It contains all the
162  * information necessary to handle remote file on the client side.
163  *
164  * Note on file sizes:  we keep two file sizes in the smbnode: the size
165  * according to the client (r_size) and the size according to the server
166  * (r_attr.fa_size).  They can differ because we modify r_size during a
167  * write system call (smbfs_rdwr), before the write request goes over the
168  * wire (before the file is actually modified on the server).  If an OTW
169  * request occurs before the cached data is written to the server the file
170  * size returned from the server (r_attr.fa_size) may not match r_size.
171  * r_size is the one we use, in general.  r_attr.fa_size is only used to
172  * determine whether or not our cached data is valid.
173  *
174  * Each smbnode has 3 locks associated with it (not including the smbnode
175  * "hash" AVL tree and free list locks):
176  *
177  *	r_rwlock:	Serializes smbfs_write and smbfs_setattr requests
178  *			and allows smbfs_read requests to proceed in parallel.
179  *			Serializes reads/updates to directories.
180  *
181  *	r_lkserlock:	Serializes lock requests with map, write, and
182  *			readahead operations.
183  *
184  *	r_statelock:	Protects all fields in the smbnode except for
185  *			those listed below.  This lock is intented
186  *			to be held for relatively short periods of
187  *			time (not accross entire putpage operations,
188  *			for example).
189  *
190  * The following members are protected by the mutex smbfreelist_lock:
191  *	r_freef
192  *	r_freeb
193  *
194  * The following members are protected by the AVL tree rwlock:
195  *	r_avl_node	(r__hdr.hdr_avl_node)
196  *
197  * Note: r_modaddr is only accessed when the r_statelock mutex is held.
198  *	Its value is also controlled via r_rwlock.  It is assumed that
199  *	there will be only 1 writer active at a time, so it safe to
200  *	set r_modaddr and release r_statelock as long as the r_rwlock
201  *	writer lock is held.
202  *
203  * 64-bit offsets: the code formerly assumed that atomic reads of
204  * r_size were safe and reliable; on 32-bit architectures, this is
205  * not true since an intervening bus cycle from another processor
206  * could update half of the size field.  The r_statelock must now
207  * be held whenever any kind of access of r_size is made.
208  *
209  * Lock ordering:
210  * 	r_rwlock > r_lkserlock > r_statelock
211  */
212 
213 typedef struct smbnode {
214 	/* Our linkage in the node cache AVL tree (see above). */
215 	smbfs_node_hdr_t	r__hdr;
216 
217 	/* short-hand names for r__hdr members */
218 #define	r_avl_node	r__hdr.hdr_avl_node
219 #define	n_rpath		r__hdr.hdr_n_rpath
220 #define	n_rplen		r__hdr.hdr_n_rplen
221 
222 	smbmntinfo_t	*n_mount;	/* VFS data */
223 	vnode_t		*r_vnode;	/* associated vnode */
224 
225 	/*
226 	 * Linkage in smbfreelist, for reclaiming nodes.
227 	 * Lock for the free list is: smbfreelist_lock
228 	 */
229 	struct smbnode	*r_freef;	/* free list forward pointer */
230 	struct smbnode	*r_freeb;	/* free list back pointer */
231 
232 	smbfs_rwlock_t	r_rwlock;	/* serialize write/setattr requests */
233 	smbfs_rwlock_t	r_lkserlock;	/* serialize lock with other ops */
234 	kmutex_t	r_statelock;	/* protect (most) smbnode fields */
235 
236 	/*
237 	 * File handle, directory search handle,
238 	 * and reference counts for them, etc.
239 	 * Lock for these is: r_lkserlock
240 	 */
241 	int		n_dirrefs;
242 	struct smbfs_fctx	*n_dirseq;	/* ff context */
243 	int		n_dirofs;	/* last ff offset */
244 	int		n_fidrefs;
245 	uint16_t	n_fid;		/* file handle */
246 	enum vtype	n_ovtype;	/* vnode type opened */
247 	uint32_t	n_rights;	/* granted rights */
248 	int		n_vcgenid;	/* gereration no. (reconnect) */
249 
250 	/*
251 	 * Misc. bookkeeping
252 	 */
253 	cred_t		*r_cred;	/* current credentials */
254 	u_offset_t	r_nextr;	/* next read offset (read-ahead) */
255 	long		r_mapcnt;	/* count of mmapped pages */
256 	uint_t		r_count;	/* # of refs not reflect in v_count */
257 	uint_t		r_awcount;	/* # of outstanding async write */
258 	uint_t		r_gcount;	/* getattrs waiting to flush pages */
259 	uint_t		r_flags;	/* flags, see below */
260 	uint32_t	n_flag;		/* NXXX flags below */
261 	uint_t		r_error;	/* async write error */
262 	kcondvar_t	r_cv;		/* condvar for blocked threads */
263 	avl_tree_t	r_dir;		/* cache of readdir responses */
264 	rddir_cache	*r_direof;	/* pointer to the EOF entry */
265 	kthread_t	*r_serial;	/* id of purging thread */
266 	list_t		r_indelmap;	/* list of delmap callers */
267 
268 	/*
269 	 * Attributes: local, and as last seen on the server.
270 	 * See notes above re: r_size vs r_attr.fa_size, etc.
271 	 */
272 	smbfattr_t	r_attr;		/* attributes from the server */
273 	hrtime_t	r_attrtime;	/* time attributes become invalid */
274 	hrtime_t	r_mtime;	/* client time file last modified */
275 	len_t		r_size;		/* client's view of file size */
276 
277 	/*
278 	 * Other attributes, not carried in smbfattr_t
279 	 */
280 	u_longlong_t	n_ino;
281 	uid_t		n_uid;
282 	gid_t		n_gid;
283 	mode_t		n_mode;
284 } smbnode_t;
285 
286 /*
287  * Flag bits in: smbnode_t .n_flag
288  */
289 #define	NFLUSHINPROG	0x00001
290 #define	NFLUSHWANT	0x00002 /* they should gone ... */
291 #define	NMODIFIED	0x00004 /* bogus, until async IO implemented */
292 #define	NREFPARENT	0x00010 /* node holds parent from recycling */
293 #define	NGOTIDS		0x00020
294 #define	NRDIRSERIAL	0x00080	/* serialize readdir operation */
295 #define	NISMAPPED	0x00800
296 #define	NFLUSHWIRE	0x01000
297 #define	NATTRCHANGED	0x02000 /* kill cached attributes at close */
298 #define	NALLOC		0x04000 /* being created */
299 #define	NWALLOC		0x08000 /* awaiting creation */
300 #define	N_XATTR 	0x10000 /* extended attribute (dir or file) */
301 
302 /*
303  * Flag bits in: smbnode_t .r_flags
304  */
305 #define	RREADDIRPLUS	0x1	/* issue a READDIRPLUS instead of READDIR */
306 #define	RDIRTY		0x2	/* dirty pages from write operation */
307 #define	RSTALE		0x4	/* file handle is stale */
308 #define	RMODINPROGRESS	0x8	/* page modification happening */
309 #define	RTRUNCATE	0x10	/* truncating, don't commit */
310 #define	RHAVEVERF	0x20	/* have a write verifier to compare against */
311 #define	RCOMMIT		0x40	/* commit in progress */
312 #define	RCOMMITWAIT	0x80	/* someone is waiting to do a commit */
313 #define	RHASHED		0x100	/* smbnode is in the "hash" AVL tree */
314 #define	ROUTOFSPACE	0x200	/* an out of space error has happened */
315 #define	RDIRECTIO	0x400	/* bypass the buffer cache */
316 #define	RLOOKUP		0x800	/* a lookup has been performed */
317 #define	RWRITEATTR	0x1000	/* attributes came from WRITE */
318 #define	RINDNLCPURGE	0x2000	/* in the process of purging DNLC references */
319 #define	RDELMAPLIST	0x4000	/* delmap callers tracking for as callback */
320 
321 /*
322  * Convert between vnode and smbnode
323  */
324 #define	VTOSMB(vp)	((smbnode_t *)((vp)->v_data))
325 #define	SMBTOV(np)	((np)->r_vnode)
326 
327 /*
328  * A macro to compute the separator that should be used for
329  * names under some directory.  See smbfs_fullpath().
330  */
331 #define	SMBFS_DNP_SEP(dnp) \
332 	(((dnp->n_flag & N_XATTR) == 0 && dnp->n_rplen > 1) ? '\\' : '\0')
333 
334 #ifdef __cplusplus
335 }
336 #endif
337 
338 #endif /* _FS_SMBFS_NODE_H_ */
339