ncc3-null.diff

csaba.henk, 03/29/2006 10:02 AM

Download (14.2 KB)

View differences:

sys/vfs/nullfs/null.h Wed Mar 29 10:29:08 2006 +0200
44 44
};
45 45

  
46 46
struct null_mount {
47
	struct mount	*nullm_vfs;
48
	struct vnode	*nullm_rootvp;	/* Reference to root null_node */
47
	struct namecache *nullm_ncp;
49 48
};
50 49

  
51 50
#ifdef _KERNEL
51

  
52 52
#define	MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data))
53

  
54 53
#ifdef NULLFS_DEBUG
55
#define NULLFSDEBUG(format, args...) printf(format ,## args)
54
#define NULLFSDEBUG(format, args...) \
55
	printf(" [nullfs] %s:%d: " format, __func__, __LINE__, ## args)
56
#define	NULLNCDEBUG(ncp)							\
57
        NULLFSDEBUG(#ncp " %p: name %s, refs %d, exlocks %d, nc_flag 0x%x, "	\
58
	            "nc_mount %p, nc_shadowed %p, nc_shadowinfo %p, "		\
59
	            "nc_shadowheight %d, nc_vp %p\n",				\
60
	            (ncp), (ncp)->nc_name, (ncp)->nc_refs,			\
61
	            (ncp)->nc_shadowinfo->sh_exlocks, (ncp)->nc_flag,		\
62
	            (ncp)->nc_mount, (ncp)->nc_shadowed,			\
63
	            (ncp)->nc_shadowinfo, (ncp)->nc_shadowheight, (ncp)->nc_vp)
56 64
#else
57 65
#define NULLFSDEBUG(format, args...)
66
#define NULLNCDEBUG(ncp)
58 67
#endif /* NULLFS_DEBUG */
59 68

  
60 69
#endif /* _KERNEL */
sys/vfs/nullfs/null_vfsops.c Wed Mar 29 10:29:08 2006 +0200
53 53
#include <sys/vnode.h>
54 54
#include <sys/mount.h>
55 55
#include <sys/nlookup.h>
56
#include <sys/namecache.h>
56 57
#include "null.h"
57 58

  
58 59
extern struct vnodeopv_entry_desc null_vnodeop_entries[];
......
80 81
{
81 82
	int error = 0;
82 83
	struct null_args args;
83
	struct vnode *rootvp;
84 84
	struct null_mount *xmp;
85 85
	u_int size;
86
	struct nlookupdata nd;
87

  
88
	NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
86

  
87
	NULLFSDEBUG("mp %p\n", (void *)mp);
89 88

  
90 89
	/*
91 90
	 * Update is a no-op
......
98 97
	 * Get argument
99 98
	 */
100 99
	error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
101
	if (error)
100

  
101
	xmp = malloc(sizeof(*xmp), M_NULLFSMNT, M_WAITOK | M_ZERO);
102

  
103
	NULLFSDEBUG("nlookup %s\n", args.target);
104

  
105
	xmp->nullm_ncp = nlookup_simple(args.target,
106
		              UIO_SYSSPACE, NLC_FOLLOW, &error);
107

  
108
	if (! xmp->nullm_ncp) {
109
		free(xmp, M_NULLFSMNT);
102 110
		return (error);
103

  
104
	/*
105
	 * Find lower node
106
	 */
107
	rootvp = NULL;
108
	error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW);
109
	if (error == 0)
110
		error = nlookup(&nd);
111
	if (error == 0) {
112
		error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, 
113
					&rootvp);
114
	}
115

  
116
	xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
117
				M_NULLFSMNT, M_WAITOK);	/* XXX */
118

  
119
	/*
120
	 * Save reference to underlying FS
121
	 */
122
        /*
123
         * As lite stacking enters the scene, the old way of doing this
124
	 * -- via the vnode -- is not good enough anymore...
125
	 */
126
	xmp->nullm_vfs = nd.nl_ncp->nc_mount;
127
	nlookup_done(&nd);
128

  
129
	vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops, 
130
			 null_vnodeop_entries, 0);
131

  
132
	VOP_UNLOCK(rootvp, 0, td);
133

  
134
	/*
135
	 * Keep a held reference to the root vnode.
136
	 * It is vrele'd in nullfs_unmount.
137
	 */
138
	xmp->nullm_rootvp = rootvp;
139
	/*
140
	 * XXX What's the proper safety condition for querying
141
	 * the underlying mount? Is this flag tuning necessary
142
	 * at all?
143
	 */
144
	if (xmp->nullm_vfs->mnt_flag & MNT_LOCAL)
111
	}
112

  
113
	cache_unlock(xmp->nullm_ncp);
114

  
115
	vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops, null_vnodeop_entries, 0);
116

  
117
	if (xmp->nullm_ncp->nc_mount->mnt_flag & MNT_LOCAL)
145 118
		mp->mnt_flag |= MNT_LOCAL;
146
	mp->mnt_data = (qaddr_t) xmp;
119
	mp->mnt_data = (void *)xmp;
147 120
	vfs_getnewfsid(mp);
148 121

  
149 122
	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
150 123
	    &size);
151 124
	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
152
	(void)nullfs_statfs(mp, &mp->mnt_stat, td);
153
	NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
154
		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntfromname);
155
	return (0);
156
}
157

  
158
/*
159
 * Free reference to null layer
160
 */
125
	NULLFSDEBUG("lower %s, alias at %s\n",
126
	            mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
127
	return (0);
128
}
129

  
161 130
static int
162 131
nullfs_unmount(struct mount *mp, int mntflags, struct thread *td)
163 132
{
164
	void *mntdata;
165
	int flags = 0;
166

  
167
	NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
168

  
169
	if (mntflags & MNT_FORCE)
170
		flags |= FORCECLOSE;
171

  
172
	/*
173
	 * Finally, throw away the null_mount structure
174
	 */
175
	mntdata = mp->mnt_data;
176
	mp->mnt_data = 0;
177
	free(mntdata, M_NULLFSMNT);
178
	return 0;
133
	NULLNCDEBUG(mp->mnt_ncp);
134

  
135
	cache_drop(MOUNTTONULLMOUNT(mp)->nullm_ncp);
136
	free(mp->mnt_data, M_NULLFSMNT);
137

  
138
	return (0);
139
}
140

  
141
static int
142
nullfs_start(struct mount *mp, int flags, struct thread *td)
143
{
144
	mp->mnt_ncp->nc_shadowed = MOUNTTONULLMOUNT(mp)->nullm_ncp;
145

  
146
	return (0);
179 147
}
180 148

  
181 149
static int
182 150
nullfs_root(struct mount *mp, struct vnode **vpp)
183 151
{
184
	struct thread *td = curthread;	/* XXX */
185
	struct vnode *vp;
186

  
187
	NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", (void *)mp,
188
	    (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp);
189

  
190
	/*
191
	 * Return locked reference to root.
192
	 */
193
	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
194
	vref(vp);
195

  
196
#ifdef NULLFS_DEBUG
197
	if (VOP_ISLOCKED(vp, NULL)) {
198
		Debugger("root vnode is locked.\n");
199
		vrele(vp);
200
		return (EDEADLK);
201
	}
202
#endif
203
	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
204
	*vpp = vp;
205
	return 0;
152
	int error;
153

  
154
	error = cache_vget(MOUNTTONULLMOUNT(mp)->nullm_ncp,
155
	                   crhold(proc0.p_ucred), LK_EXCLUSIVE | LK_RETRY, vpp);
156
	crfree(proc0.p_ucred);
157

  
158
	return (error);
159
}
160

  
161
static __inline
162
struct mount *
163
nullfs_lowermount_0(struct mount *mp)
164
{
165
	return (MOUNTTONULLMOUNT(mp)->nullm_ncp->nc_mount);
206 166
}
207 167

  
208 168
static int
209 169
nullfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg,
210 170
		struct thread *td)
211 171
{
212
	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, td);
172
	return VFS_QUOTACTL(nullfs_lowermount_0(mp), cmd, uid, arg, td);
213 173
}
214 174

  
215 175
static int
......
218 178
	int error;
219 179
	struct statfs mstat;
220 180

  
221
	NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p)\n", (void *)mp,
222
	    (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp);
181
	NULLFSDEBUG("mp %p, ncp %p, lower mp %p\n",
182
	            mp, mp->mnt_ncp, nullfs_lowermount_0(mp));
223 183

  
224 184
	bzero(&mstat, sizeof(mstat));
225 185

  
226
	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, td);
186
	error = VFS_STATFS(nullfs_lowermount_0(mp), &mstat, td);
227 187
	if (error)
228 188
		return (error);
229 189

  
......
248 208
nullfs_checkexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
249 209
		struct ucred **credanonp)
250 210
{
251

  
252
	return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp)->nullm_vfs, nam, 
253
		extflagsp, credanonp);
211
	return VFS_CHECKEXP(nullfs_lowermount_0(mp), nam, extflagsp, credanonp);
254 212
}
255 213

  
256 214
static int                        
257 215
nullfs_extattrctl(struct mount *mp, int cmd, const char *attrname, caddr_t arg,
258 216
		  struct thread *td)
259 217
{
260
	return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname,
261
	    arg, td);
218
	return VFS_EXTATTRCTL(nullfs_lowermount_0(mp), cmd, attrname, arg, td);
262 219
}
263 220

  
264 221

  
265 222
static struct vfsops null_vfsops = {
266 223
	.vfs_mount =   	 	nullfs_mount,
267 224
	.vfs_unmount =   	nullfs_unmount,
225
	.vfs_start =            nullfs_start,
268 226
	.vfs_root =     	nullfs_root,
269 227
	.vfs_quotactl =   	nullfs_quotactl,
270 228
	.vfs_statfs =    	nullfs_statfs,
sys/vfs/nullfs/null_vnops.c Wed Mar 29 10:29:08 2006 +0200
98 98
 * might be able to get on with a hybrid solution: overlay some vnodes, and rely
99 99
 * on namecache API for the rest.
100 100
 */
101
 
101

  
102 102
#include <sys/param.h>
103 103
#include <sys/systm.h>
104 104
#include <sys/kernel.h>
......
109 109
#include <sys/namei.h>
110 110
#include <sys/malloc.h>
111 111
#include <sys/buf.h>
112
#include <sys/namecache.h>
113
#include <sys/nlookup.h>
112 114
#include "null.h"
113 115

  
114 116
static int	null_nresolve(struct vop_nresolve_args *ap);
......
122 124
static int	null_nrmdir(struct vop_nrmdir_args *ap);
123 125
static int	null_nrename(struct vop_nrename_args *ap);
124 126

  
127
static __inline
128
struct mount *
129
nullfs_lowermount_l(struct namecache *ncp)
130
{
131
	/*
132
	 * The code in use below allows allows passing through lower mounts.
133
	 * If we didn't want to do that, we could use
134
	 *
135
	 *   MOUNTTONULLMOUNT(ncp->nc_mount)->nullm_ncp->nc_mount
136
	 *
137
	 * Eventually, the choice might be configurable.
138
	 */
139
	return (ncp->nc_shadowed->nc_mount);
140
}
141

  
142

  
143
static __inline
144
int
145
nullfs_check(struct namecache *ncp)
146
{
147
	if (ncp->nc_mount->mnt_ncp == ncp)
148
		return (EPERM);
149

  
150
	if (!ncp->nc_shadowed)
151
		return (ENOENT);
152

  
153
	if (ncp->nc_shadowheight == 0)
154
		return (EINVAL);
155

  
156
	return (0);
157
}
158

  
125 159
static int
126 160
null_nresolve(struct vop_nresolve_args *ap)
127 161
{
128
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
129

  
130
	return vop_nresolve_ap(ap);
131
}
132

  
133
static int
134
null_ncreate(struct vop_ncreate_args *ap)
135
{
136
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
137

  
138
	return vop_ncreate_ap(ap);
139
}
140

  
141
static int
142
null_nmkdir(struct vop_nmkdir_args *ap)
143
{
144
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
145

  
146
	return vop_nmkdir_ap(ap);
147
}
148

  
149
static int
150
null_nmknod(struct vop_nmknod_args *ap)
151
{
152
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
153

  
154
	return vop_nmknod_ap(ap);
155
}
156

  
157
static int
158
null_nlink(struct vop_nlink_args *ap)
159
{
160
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
161

  
162
	return vop_nlink_ap(ap);
163
}
164

  
165
static int
166
null_nsymlink(struct vop_nsymlink_args *ap)
167
{
168
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
169

  
170
	return vop_nsymlink_ap(ap);
171
}
172

  
173
static int
174
null_nwhiteout(struct vop_nwhiteout_args *ap)
175
{
176
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
177

  
178
	return vop_nwhiteout_ap(ap);
179
}
180

  
181
static int
182
null_nremove(struct vop_nremove_args *ap)
183
{
184
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
185

  
186
	return vop_nremove_ap(ap);
187
}
188

  
189
static int
190
null_nrmdir(struct vop_nrmdir_args *ap)
191
{
192
	ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
193

  
194
	return vop_nrmdir_ap(ap);
195
}
162
	struct namecache *ncp = ap->a_ncp;
163
	struct nlcomponent nlc;
164
	struct namecache *sncp, *psncp;
165
	int error = 0;
166

  
167
	sncp = ncp->nc_shadow_next;
168
	if (sncp) {
169
		cache_hold(sncp);
170
		cache_setunresolved(sncp);
171
		cache_put(sncp);
172
	}
173

  
174
	cache_unlock(ncp);
175
	cache_lock(ncp->nc_parent);
176
	psncp = ncp->nc_parent->nc_shadowed;
177
	if (psncp)
178
		cache_hold(psncp);
179
	cache_unlock(ncp->nc_parent);
180

  
181
	if (! psncp) {
182
		cache_lock(ncp);
183
		if ((ncp->nc_flag & NCF_UNRESOLVED) == 0)
184
			cache_setvp(ncp, NULL);
185
		return (ncp->nc_error);
186
	}
187

  
188
	nlc.nlc_nameptr = ncp->nc_name;
189
	nlc.nlc_namelen = ncp->nc_nlen;
190
	sncp = cache_nlookup(psncp, &nlc);
191
	cache_drop(psncp);
192

  
193
	if ((sncp->nc_flag & NCF_UNRESOLVED) == 0)
194
		goto postdowncall;
195

  
196
	ap->a_head.a_ops = sncp->nc_mount->mnt_vn_use_ops;
197
	ap->a_ncp = sncp;
198
	/*
199
	 * According to cache_resolve(), the primary place for
200
	 * VOP_NRESOLVE calls, the caller of the nresolve method
201
	 * is the one who should take care about ncp->nc_error.
202
	 */
203
	ap->a_ncp->nc_error = vop_nresolve_ap(ap);
204

  
205
postdowncall:
206

  
207
	error = cache_shadow_attach(ncp, sncp);
208

  
209
	NULLNCDEBUG(ncp);
210
	NULLNCDEBUG(sncp);
211
	NULLFSDEBUG("attach error %d\n", error);
212

  
213
	if (error) {
214
		cache_put(sncp);
215
		if (ncp->nc_flag & NCF_UNRESOLVED) {
216
			cache_setvp(ncp, NULL);
217
			error = ENOENT;
218
		} else if (error == EEXIST)
219
			error = ncp->nc_error;
220
	} else {
221
		error = sncp->nc_error;
222
		cache_setvp(ncp, sncp->nc_vp);
223
		ncp->nc_shadowed = sncp;
224
		cache_drop(sncp);
225
	}
226

  
227
	NULLFSDEBUG("error %d\n", error);
228
	return (error);
229
}
230

  
231
#define NULL_NVOP_TEMPLATE(OP)							\
232
static int									\
233
null_ ## OP(struct vop_ ## OP ## _args *ap)					\
234
{										\
235
	struct namecache *ncp = ap->a_ncp;					\
236
	struct namecache *sncp = ncp->nc_shadowed;				\
237
	int error;								\
238
										\
239
	NULLNCDEBUG(ap->a_ncp);							\
240
										\
241
	if ((error = nullfs_check(ncp)))					\
242
		return (error);							\
243
	cache_hold(sncp);							\
244
										\
245
	NULLNCDEBUG(ap->a_ncp->nc_shadowed);					\
246
										\
247
	ap->a_head.a_ops = nullfs_lowermount_l(ap->a_ncp)->mnt_vn_use_ops;	\
248
	ap->a_ncp = ncp->nc_shadowed;						\
249
										\
250
	error = vop_ ## OP ## _ap(ap);						\
251
	NULLNCDEBUG(ncp);							\
252
	NULLNCDEBUG(sncp);							\
253
	sncp->nc_shadowinfo == ncp->nc_shadowinfo ?				\
254
	    cache_drop(sncp) :							\
255
	    cache_put(sncp);							\
256
										\
257
	return (error);								\
258
}
259

  
260
NULL_NVOP_TEMPLATE(ncreate)
261
NULL_NVOP_TEMPLATE(nmkdir)
262
NULL_NVOP_TEMPLATE(nmknod)
263
NULL_NVOP_TEMPLATE(nlink)
264
NULL_NVOP_TEMPLATE(nsymlink)
265
NULL_NVOP_TEMPLATE(nwhiteout)
266
NULL_NVOP_TEMPLATE(nremove)
267
NULL_NVOP_TEMPLATE(nrmdir)
196 268

  
197 269
static int
198 270
null_nrename(struct vop_nrename_args *ap)
199 271
{
272
	struct namecache *fncp = ap->a_fncp;
273
	struct namecache *tncp = ap->a_tncp;
274
	struct namecache *sfncp = fncp->nc_shadowed;
275
	struct namecache *stncp = tncp->nc_shadowed;
200 276
	struct mount *lmp;
201

  
202
	lmp = MOUNTTONULLMOUNT(ap->a_fncp->nc_mount)->nullm_vfs;
203
	if (lmp != MOUNTTONULLMOUNT(ap->a_tncp->nc_mount)->nullm_vfs)
204
		return (EINVAL);
205

  
206
	ap->a_head.a_ops = lmp->mnt_vn_norm_ops;
207

  
208
	return vop_nrename_ap(ap);
277
	int error;
278

  
279
	NULLNCDEBUG(ap->a_fncp);
280
	NULLNCDEBUG(ap->a_tncp);
281

  
282
	if ((error = nullfs_check(fncp)))
283
		return (error);
284
	if ((error = nullfs_check(tncp)))
285
		return (error);
286

  
287
	lmp = nullfs_lowermount_l(fncp);
288
	if (lmp != nullfs_lowermount_l(tncp))
289
		return (EXDEV);
290

  
291
	cache_hold(sfncp);
292
	cache_hold(stncp);
293

  
294
	NULLNCDEBUG(ap->a_fncp->nc_shadowed);
295
	NULLNCDEBUG(ap->a_tncp->nc_shadowed);
296

  
297
	ap->a_head.a_ops = lmp->mnt_vn_use_ops;
298
	ap->a_fncp = fncp->nc_shadowed;
299
	ap->a_tncp = tncp->nc_shadowed;
300

  
301
	error = vop_nrename_ap(ap);
302

  
303
	sfncp->nc_shadowinfo == fncp->nc_shadowinfo ?
304
	    cache_drop(sfncp) :
305
	    cache_put(sfncp);
306
	stncp->nc_shadowinfo == tncp->nc_shadowinfo ?
307
	    cache_drop(stncp) :
308
	    cache_put(stncp);
309

  
310
	return (error);
209 311
}
210 312

  
211 313
/*
......
224 326
	{ &vop_nrename_desc,		(vnodeopv_entry_t) null_nrename },
225 327
	{ NULL, NULL }
226 328
};
227