xref: /dragonfly/sys/vfs/dirfs/dirfs.h (revision 926deccb)
1 /*
2  * Copyright (c) 2013 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Antonio Huete Jimenez <tuxillo@quantumachine.net>
6  * by Matthew Dillon <dillon@dragonflybsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36 
37 #ifndef _SYS_VFS_DIRFS_DIRFS_H_
38 #define _SYS_VFS_DIRFS_DIRFS_H_
39 
40 #include <unistd.h>
41 
42 #include <sys/lockf.h>
43 #include <sys/stat.h>
44 #include <sys/vnode.h>
45 
46 MALLOC_DECLARE(M_DIRFS);
47 MALLOC_DECLARE(M_DIRFS_NODE);
48 MALLOC_DECLARE(M_DIRFS_MISC);
49 
50 #ifndef KTR_DIRFS
51 #define KTR_DIRFS KTR_ALL
52 #endif
53 
54 #define DIRFS_NOFD	-1	/* No fd present */
55 
56 #define DIRFS_ROOT	0x00000001
57 #define DIRFS_PASVFD	0x00000002
58 
59 #define DIRFS_TXTFLG "pasvfd"
60 
61 /* Used for buffer cache operations */
62 #define BSIZE	16384
63 #define BMASK	(BSIZE - 1)
64 
65 /*
66  * XXX This should be temporary. A semi-proper solution would be to expose
67  * below prototypes in the _KERNEL_VIRTUAL case.
68  */
69 extern int getdirentries(int, char *, int, long *);
70 extern int statfs(const char *, struct statfs *);
71 
72 /*
73  * Debugging macros. The impact should be determined and in case it has a
74  * considerable performance penalty, it should be enclosed in a DEBUG #ifdef.
75  */
76 #define debug_called() do {					\
77 		dbg(9, "called\n", __func__);			\
78 } while(0)
79 
80 #define dbg(lvl, fmt, ...) do {					\
81 		debug(lvl, "%s: " fmt, __func__, ##__VA_ARGS__);	\
82 } while(0)
83 
84 #define debug_node(s) do {						\
85 		dbg(5, "mode=%u flags=%u dn_name=%s "			\
86 		    "uid=%u gid=%u objtype=%u nlinks=%d "		\
87 		    "size=%jd ctime=%ju atime=%ju mtime=%ju\n",		\
88 		    s->dn_mode, s->dn_flags, s->dn_name,		\
89 		    s->dn_uid, s->dn_gid, s->dn_type,			\
90 		    s->dn_links, s->dn_size,				\
91 		    s->dn_ctime, s->dn_atime,				\
92 		    s->dn_mtime);					\
93 } while(0)
94 
95 #define debug_node2(n) do {						\
96 		dbg(5, "dnp=%p name=%s fd=%d parent=%p vnode=%p "	\
97 		    "refcnt=%d state=%s\n",				\
98 		    n, n->dn_name, n->dn_fd, n->dn_parent, n->dn_vnode,	\
99 		    n->dn_refcnt, dirfs_flag2str(n));			\
100 } while(0)
101 
102 /*
103  * Locking macros
104  */
105 #define dirfs_node_islocked(n)	(lockstatus(&(n)->dn_lock,curthread) == LK_EXCLUSIVE)
106 #define dirfs_node_lock(n)	lockmgr(&(n)->dn_lock, LK_EXCLUSIVE|LK_RETRY)
107 #define dirfs_node_unlock(n) 	lockmgr(&(n)->dn_lock, LK_RELEASE)
108 #define dirfs_mount_lock(m)	lockmgr(&(m)->dm_lock, LK_EXCLUSIVE|LK_RETRY)
109 #define dirfs_mount_unlock(m)	lockmgr(&(m)->dm_lock, LK_RELEASE)
110 #define dirfs_mount_gettoken(m)	lwkt_gettoken(&(m)->dm_token)
111 #define dirfs_mount_reltoken(m)	lwkt_reltoken(&(m)->dm_token)
112 
113 #define dirfs_node_isroot(n)	(n->dn_state & DIRFS_ROOT)
114 
115 /*
116  * Main in-memory node structure which will represent a host file when active.
117  * Upon VOP_NRESOLVE() an attempt to initialize its generic fields will be made
118  * via a fstatat(2)/lstat(2) call.
119  */
120 struct dirfs_node {
121 	enum vtype		dn_type;	/* Node type. Same as vnode
122 						   type for simplicty */
123 
124 	int			dn_state;	/* Node state flags */
125 
126 	TAILQ_ENTRY(dirfs_node)	dn_fdentry;	/* Passive fd cache */
127 	RB_ENTRY(dirfs_node)	dn_rbentry;	/* Inode no. lookup */
128 
129 	int			dn_refcnt;	/* Refs from children */
130 	int			dn_fd;		/* File des. for open(2) */
131 
132 	struct dirfs_node *	dn_parent;	/* Pointer to parent node */
133 
134 	struct vnode *          dn_vnode;	/* Reference to its vnode on
135 						   the vkernel scope */
136 	char *			dn_name;
137 	int			dn_namelen;
138 
139         struct lockf            dn_advlock;
140 	struct lock		dn_lock;
141 
142 	uint32_t		dn_st_dev;	/* Device number */
143 
144 	/* Generic attributes */
145 	ino_t			dn_ino;
146 	long			dn_blocksize;
147 	uid_t			dn_uid;
148 	gid_t			dn_gid;
149 	mode_t			dn_mode;
150 	int			dn_flags;
151 	nlink_t			dn_links;
152 	int32_t			dn_atime;
153 	int32_t			dn_atimensec;
154 	int32_t			dn_mtime;
155 	int32_t			dn_mtimensec;
156 	int32_t			dn_ctime;
157 	int32_t			dn_ctimensec;
158 	unsigned long		dn_gen;
159 	off_t			dn_size;
160 };
161 typedef struct dirfs_node *dirfs_node_t;
162 
163 /*
164  * In-memory dirfs mount structure. It corresponds to a mounted
165  * dirfs filesystem.
166  */
167 struct dirfs_mount {
168 	RB_HEAD(, dn_rbentry) dm_inotree;
169 	TAILQ_HEAD(, dirfs_node) dm_fdlist;
170 
171 	struct lock	 	dm_lock;
172 	struct lwkt_token	dm_token;
173 	dirfs_node_t		dm_root;	/* Root dirfs node */
174 	struct mount *		dm_mount;
175 	int			dm_rdonly;
176 
177 	int			dm_fd_used;	/* Opened file descriptors */
178 
179 	char			dm_path[MAXPATHLEN];
180 };
181 typedef struct dirfs_mount *dirfs_mount_t;
182 
183 /*
184  * VFS <-> DIRFS conversion macros
185  */
186 #define VFS_TO_DIRFS(mp)	((dirfs_mount_t)((mp)->mnt_data))
187 #define DIRFS_TO_VFS(dmp)	((struct mount *)((dmp)->dm_mount))
188 #define VP_TO_NODE(vp)		((dirfs_node_t)((vp)->v_data))
189 #define NODE_TO_VP(dnp)		((dnp)->dn_vnode)
190 
191 /* Misc stuff */
192 extern int debuglvl;
193 extern int dirfs_fd_limit;
194 extern int dirfs_fd_used;
195 extern long passive_fd_list_miss;
196 extern long passive_fd_list_hits;
197 
198 extern struct vop_ops dirfs_vnode_vops;
199 
200 /*
201  * Misc functions for node flags and reference count
202  */
203 static __inline void
204 dirfs_node_ref(dirfs_node_t dnp)
205 {
206 	atomic_add_int(&dnp->dn_refcnt, 1);
207 }
208 
209 static __inline int
210 dirfs_node_unref(dirfs_node_t dnp)
211 {
212 	/*
213 	 * Returns non-zero on last unref.
214 	 */
215 	KKASSERT(dnp->dn_refcnt > 0);
216 	return (atomic_fetchadd_int(&dnp->dn_refcnt, -1) == 1);
217 }
218 
219 static __inline void
220 dirfs_node_setflags(dirfs_node_t dnp, int flags)
221 {
222 	atomic_set_int(&dnp->dn_state, flags);
223 }
224 
225 static __inline void
226 dirfs_node_clrflags(dirfs_node_t dnp, int flags)
227 {
228 	atomic_clear_int(&dnp->dn_state, flags);
229 }
230 
231 
232 /*
233  * Prototypes
234  */
235 dirfs_node_t dirfs_node_alloc(struct mount *);
236 int dirfs_node_stat(int, const char *, dirfs_node_t);
237 int dirfs_nodetype(struct stat *);
238 void dirfs_node_setname(dirfs_node_t, const char *, int);
239 char *dirfs_node_fullpath(dirfs_mount_t, const char *);
240 int dirfs_node_free(dirfs_mount_t, dirfs_node_t);
241 void dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp);
242 void dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state);
243 void dirfs_alloc_vp(struct mount *, struct vnode **, int, dirfs_node_t);
244 void dirfs_free_vp(dirfs_mount_t, dirfs_node_t);
245 int dirfs_alloc_file(dirfs_mount_t, dirfs_node_t *, dirfs_node_t,
246     struct namecache *, struct vnode **, struct vattr *, int);
247 dirfs_node_t dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur,
248 			char **pathto, char **pathfree);
249 void dirfs_dropfd(dirfs_mount_t dmp, dirfs_node_t dnp1, char *pathfree);
250 char *dirfs_node_absolute_path(dirfs_mount_t, dirfs_node_t, char **);
251 char *dirfs_node_absolute_path_plus(dirfs_mount_t, dirfs_node_t,
252 			char *, char **);
253 int dirfs_open_helper(dirfs_mount_t, dirfs_node_t, int, char *);
254 int dirfs_close_helper(dirfs_node_t);
255 int dirfs_node_refcnt(dirfs_node_t);
256 char *dirfs_flag2str(dirfs_node_t);
257 int dirfs_node_getperms(dirfs_node_t, int *, int *, int *);
258 int dirfs_node_chflags(dirfs_node_t, int, struct ucred *);
259 int dirfs_node_chtimes(dirfs_node_t);
260 int dirfs_node_chmod(dirfs_mount_t, dirfs_node_t, mode_t cur_mode);
261 int dirfs_node_chown(dirfs_mount_t, dirfs_node_t,
262 			uid_t cur_uid, uid_t cur_gid, mode_t cur_mode);
263 int dirfs_node_chsize(dirfs_node_t, off_t);
264 void debug(int, const char *, ...);
265 
266 #endif /* _SYS_VFS_DIRFS_DIRFS_H_ */
267