]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c
Fix BIND named(8) cache poisoning with DNSSEC validation.
[FreeBSD/releng/7.2.git] / sys / cddl / contrib / opensolaris / uts / common / fs / zfs / zfs_replay.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25
26 #pragma ident   "%Z%%M% %I%     %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/sysmacros.h>
32 #include <sys/cmn_err.h>
33 #include <sys/kmem.h>
34 #include <sys/file.h>
35 #include <sys/fcntl.h>
36 #include <sys/vfs.h>
37 #include <sys/fs/zfs.h>
38 #include <sys/zfs_znode.h>
39 #include <sys/zfs_dir.h>
40 #include <sys/zfs_acl.h>
41 #include <sys/spa.h>
42 #include <sys/zil.h>
43 #include <sys/byteorder.h>
44 #include <sys/stat.h>
45 #include <sys/acl.h>
46 #include <sys/atomic.h>
47 #include <sys/cred.h>
48 #include <sys/namei.h>
49
50 /*
51  * Functions to replay ZFS intent log (ZIL) records
52  * The functions are called through a function vector (zfs_replay_vector)
53  * which is indexed by the transaction type.
54  */
55
56 static void
57 zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
58         uint64_t uid, uint64_t gid, uint64_t rdev, uint64_t nodeid)
59 {
60         VATTR_NULL(vap);
61         vap->va_mask = (uint_t)mask;
62         if (mask & AT_TYPE)
63                 vap->va_type = IFTOVT(mode);
64         if (mask & AT_MODE)
65                 vap->va_mode = mode & MODEMASK;
66         if (mask & AT_UID)
67                 vap->va_uid = (uid_t)uid;
68         if (mask & AT_GID)
69                 vap->va_gid = (gid_t)gid;
70         vap->va_rdev = zfs_cmpldev(rdev);
71         vap->va_nodeid = nodeid;
72 }
73
74 /* ARGSUSED */
75 static int
76 zfs_replay_error(zfsvfs_t *zfsvfs, lr_t *lr, boolean_t byteswap)
77 {
78         return (ENOTSUP);
79 }
80
81 static int
82 zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
83 {
84         char *name = (char *)(lr + 1);  /* name follows lr_create_t */
85         char *link;                     /* symlink content follows name */
86         znode_t *dzp;
87         vnode_t *vp = NULL;
88         vattr_t va;
89         struct componentname cn;
90         int error;
91
92         if (byteswap)
93                 byteswap_uint64_array(lr, sizeof (*lr));
94
95         if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
96                 return (error);
97
98         zfs_init_vattr(&va, AT_TYPE | AT_MODE | AT_UID | AT_GID,
99             lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
100
101         /*
102          * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
103          * eventually end up in zfs_mknode(), which assigns the object's
104          * creation time and generation number.  The generic VOP_CREATE()
105          * doesn't have either concept, so we smuggle the values inside
106          * the vattr's otherwise unused va_ctime and va_nblocks fields.
107          */
108         ZFS_TIME_DECODE(&va.va_ctime, lr->lr_crtime);
109         va.va_nblocks = lr->lr_gen;
110
111         cn.cn_nameptr = name;
112         cn.cn_cred = kcred;
113         cn.cn_thread = curthread;
114         cn.cn_flags = SAVENAME;
115
116         vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY, curthread);
117         switch ((int)lr->lr_common.lrc_txtype) {
118         case TX_CREATE:
119                 error = VOP_CREATE(ZTOV(dzp), &vp, &cn, &va);
120                 break;
121         case TX_MKDIR:
122                 error = VOP_MKDIR(ZTOV(dzp), &vp, &cn, &va);
123                 break;
124         case TX_MKXATTR:
125                 error = zfs_make_xattrdir(dzp, &va, &vp, kcred);
126                 break;
127         case TX_SYMLINK:
128                 link = name + strlen(name) + 1;
129                 error = VOP_SYMLINK(ZTOV(dzp), &vp, &cn, &va, link);
130                 break;
131         default:
132                 error = ENOTSUP;
133         }
134         VOP_UNLOCK(ZTOV(dzp), 0, curthread);
135
136         if (error == 0 && vp != NULL) {
137                 VOP_UNLOCK(vp, 0, curthread);
138                 VN_RELE(vp);
139         }
140
141         VN_RELE(ZTOV(dzp));
142
143         return (error);
144 }
145
146 static int
147 zfs_replay_remove(zfsvfs_t *zfsvfs, lr_remove_t *lr, boolean_t byteswap)
148 {
149         char *name = (char *)(lr + 1);  /* name follows lr_remove_t */
150         znode_t *dzp;
151         struct componentname cn;
152         vnode_t *vp;
153         int error;
154
155         if (byteswap)
156                 byteswap_uint64_array(lr, sizeof (*lr));
157
158         if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
159                 return (error);
160
161         bzero(&cn, sizeof(cn));
162         cn.cn_nameptr = name;
163         cn.cn_namelen = strlen(name);
164         cn.cn_nameiop = DELETE;
165         cn.cn_flags = ISLASTCN | SAVENAME;
166         cn.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
167         cn.cn_cred = kcred;
168         cn.cn_thread = curthread;
169         vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY, curthread);
170         error = VOP_LOOKUP(ZTOV(dzp), &vp, &cn);
171         if (error != 0) {
172                 VOP_UNLOCK(ZTOV(dzp), 0, curthread);
173                 goto fail;
174         }
175
176         switch ((int)lr->lr_common.lrc_txtype) {
177         case TX_REMOVE:
178                 error = VOP_REMOVE(ZTOV(dzp), vp, &cn);
179                 break;
180         case TX_RMDIR:
181                 error = VOP_RMDIR(ZTOV(dzp), vp, &cn);
182                 break;
183         default:
184                 error = ENOTSUP;
185         }
186         vput(vp);
187         VOP_UNLOCK(ZTOV(dzp), 0, curthread);
188 fail:
189         VN_RELE(ZTOV(dzp));
190
191         return (error);
192 }
193
194 static int
195 zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
196 {
197         char *name = (char *)(lr + 1);  /* name follows lr_link_t */
198         znode_t *dzp, *zp;
199         struct componentname cn;
200         int error;
201
202         if (byteswap)
203                 byteswap_uint64_array(lr, sizeof (*lr));
204
205         if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
206                 return (error);
207
208         if ((error = zfs_zget(zfsvfs, lr->lr_link_obj, &zp)) != 0) {
209                 VN_RELE(ZTOV(dzp));
210                 return (error);
211         }
212
213         cn.cn_nameptr = name;
214         cn.cn_cred = kcred;
215         cn.cn_thread = curthread;
216         cn.cn_flags = SAVENAME;
217
218         vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY, curthread);
219         vn_lock(ZTOV(zp), LK_EXCLUSIVE | LK_RETRY, curthread);
220         error = VOP_LINK(ZTOV(dzp), ZTOV(zp), &cn);
221         VOP_UNLOCK(ZTOV(zp), 0, curthread);
222         VOP_UNLOCK(ZTOV(dzp), 0, curthread);
223
224         VN_RELE(ZTOV(zp));
225         VN_RELE(ZTOV(dzp));
226
227         return (error);
228 }
229
230 static int
231 zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, boolean_t byteswap)
232 {
233         char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */
234         char *tname = sname + strlen(sname) + 1;
235         znode_t *sdzp, *tdzp;
236         struct componentname scn, tcn;
237         vnode_t *svp, *tvp;
238         kthread_t *td = curthread;
239         int error;
240
241         if (byteswap)
242                 byteswap_uint64_array(lr, sizeof (*lr));
243
244         if ((error = zfs_zget(zfsvfs, lr->lr_sdoid, &sdzp)) != 0)
245                 return (error);
246
247         if ((error = zfs_zget(zfsvfs, lr->lr_tdoid, &tdzp)) != 0) {
248                 VN_RELE(ZTOV(sdzp));
249                 return (error);
250         }
251
252         svp = tvp = NULL;
253
254         bzero(&scn, sizeof(scn));
255         scn.cn_nameptr = sname;
256         scn.cn_namelen = strlen(sname);
257         scn.cn_nameiop = DELETE;
258         scn.cn_flags = ISLASTCN | SAVENAME;
259         scn.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
260         scn.cn_cred = kcred;
261         scn.cn_thread = td;
262         vn_lock(ZTOV(sdzp), LK_EXCLUSIVE | LK_RETRY, td);
263         error = VOP_LOOKUP(ZTOV(sdzp), &svp, &scn);
264         VOP_UNLOCK(ZTOV(sdzp), 0, td);
265         if (error != 0)
266                 goto fail;
267         VOP_UNLOCK(svp, 0, td);
268
269         bzero(&tcn, sizeof(tcn));
270         tcn.cn_nameptr = tname;
271         tcn.cn_namelen = strlen(tname);
272         tcn.cn_nameiop = RENAME;
273         tcn.cn_flags = ISLASTCN | SAVENAME;
274         tcn.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
275         tcn.cn_cred = kcred;
276         tcn.cn_thread = td;
277         vn_lock(ZTOV(tdzp), LK_EXCLUSIVE | LK_RETRY, td);
278         error = VOP_LOOKUP(ZTOV(tdzp), &tvp, &tcn);
279         if (error == EJUSTRETURN)
280                 tvp = NULL;
281         else if (error != 0) {
282                 VOP_UNLOCK(ZTOV(tdzp), 0, td);
283                 goto fail;
284         }
285
286         error = VOP_RENAME(ZTOV(sdzp), svp, &scn, ZTOV(tdzp), tvp, &tcn);
287         return (error);
288 fail:
289         if (svp != NULL)
290                 vrele(svp);
291         if (tvp != NULL)
292                 vrele(tvp);
293         VN_RELE(ZTOV(tdzp));
294         VN_RELE(ZTOV(sdzp));
295
296         return (error);
297 }
298
299 static int
300 zfs_replay_write(zfsvfs_t *zfsvfs, lr_write_t *lr, boolean_t byteswap)
301 {
302         char *data = (char *)(lr + 1);  /* data follows lr_write_t */
303         znode_t *zp;
304         int error;
305         ssize_t resid;
306
307         if (byteswap)
308                 byteswap_uint64_array(lr, sizeof (*lr));
309
310         if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
311                 /*
312                  * As we can log writes out of order, it's possible the
313                  * file has been removed. In this case just drop the write
314                  * and return success.
315                  */
316                 if (error == ENOENT)
317                         error = 0;
318                 return (error);
319         }
320
321         error = vn_rdwr(UIO_WRITE, ZTOV(zp), data, lr->lr_length,
322             lr->lr_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
323
324         VN_RELE(ZTOV(zp));
325
326         return (error);
327 }
328
329 static int
330 zfs_replay_truncate(zfsvfs_t *zfsvfs, lr_truncate_t *lr, boolean_t byteswap)
331 {
332
333         ZFS_LOG(0, "Unexpected code path, report to pjd@FreeBSD.org");
334         return (EOPNOTSUPP);
335 }
336
337 static int
338 zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap)
339 {
340         znode_t *zp;
341         vattr_t va;
342         vnode_t *vp;
343         int error;
344
345         if (byteswap)
346                 byteswap_uint64_array(lr, sizeof (*lr));
347
348         if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
349                 /*
350                  * As we can log setattrs out of order, it's possible the
351                  * file has been removed. In this case just drop the setattr
352                  * and return success.
353                  */
354                 if (error == ENOENT)
355                         error = 0;
356                 return (error);
357         }
358
359         zfs_init_vattr(&va, lr->lr_mask, lr->lr_mode,
360             lr->lr_uid, lr->lr_gid, 0, lr->lr_foid);
361
362         va.va_size = lr->lr_size;
363         ZFS_TIME_DECODE(&va.va_atime, lr->lr_atime);
364         ZFS_TIME_DECODE(&va.va_mtime, lr->lr_mtime);
365
366         vp = ZTOV(zp);
367         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
368         error = VOP_SETATTR(vp, &va, kcred, curthread);
369         VOP_UNLOCK(vp, 0, curthread);
370         VN_RELE(vp);
371
372         return (error);
373 }
374
375 static int
376 zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
377 {
378         ace_t *ace = (ace_t *)(lr + 1); /* ace array follows lr_acl_t */
379 #ifdef TODO
380         vsecattr_t vsa;
381 #endif
382         znode_t *zp;
383         int error;
384
385         if (byteswap) {
386                 byteswap_uint64_array(lr, sizeof (*lr));
387                 zfs_ace_byteswap(ace, lr->lr_aclcnt);
388         }
389
390         if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
391                 /*
392                  * As we can log acls out of order, it's possible the
393                  * file has been removed. In this case just drop the acl
394                  * and return success.
395                  */
396                 if (error == ENOENT)
397                         error = 0;
398                 return (error);
399         }
400
401 #ifdef TODO
402         bzero(&vsa, sizeof (vsa));
403         vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
404         vsa.vsa_aclcnt = lr->lr_aclcnt;
405         vsa.vsa_aclentp = ace;
406
407         error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred);
408 #else
409         error = EOPNOTSUPP;
410 #endif
411
412         VN_RELE(ZTOV(zp));
413
414         return (error);
415 }
416
417 /*
418  * Callback vectors for replaying records
419  */
420 zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE] = {
421         zfs_replay_error,       /* 0 no such transaction type */
422         zfs_replay_create,      /* TX_CREATE */
423         zfs_replay_create,      /* TX_MKDIR */
424         zfs_replay_create,      /* TX_MKXATTR */
425         zfs_replay_create,      /* TX_SYMLINK */
426         zfs_replay_remove,      /* TX_REMOVE */
427         zfs_replay_remove,      /* TX_RMDIR */
428         zfs_replay_link,        /* TX_LINK */
429         zfs_replay_rename,      /* TX_RENAME */
430         zfs_replay_write,       /* TX_WRITE */
431         zfs_replay_truncate,    /* TX_TRUNCATE */
432         zfs_replay_setattr,     /* TX_SETATTR */
433         zfs_replay_acl,         /* TX_ACL */
434 };