]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_replay.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[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         vap->va_type = IFTOVT(mode);
63         vap->va_mode = mode & MODEMASK;
64         vap->va_uid = (uid_t)uid;
65         vap->va_gid = (gid_t)gid;
66         vap->va_rdev = zfs_cmpldev(rdev);
67         vap->va_nodeid = nodeid;
68 }
69
70 /* ARGSUSED */
71 static int
72 zfs_replay_error(zfsvfs_t *zfsvfs, lr_t *lr, boolean_t byteswap)
73 {
74         return (ENOTSUP);
75 }
76
77 static int
78 zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
79 {
80         char *name = (char *)(lr + 1);  /* name follows lr_create_t */
81         char *link;                     /* symlink content follows name */
82         znode_t *dzp;
83         vnode_t *vp = NULL;
84         vattr_t va;
85         struct componentname cn;
86         int error;
87
88         if (byteswap)
89                 byteswap_uint64_array(lr, sizeof (*lr));
90
91         if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
92                 return (error);
93
94         zfs_init_vattr(&va, AT_TYPE | AT_MODE | AT_UID | AT_GID,
95             lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
96
97         /*
98          * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
99          * eventually end up in zfs_mknode(), which assigns the object's
100          * creation time and generation number.  The generic VOP_CREATE()
101          * doesn't have either concept, so we smuggle the values inside
102          * the vattr's otherwise unused va_ctime and va_nblocks fields.
103          */
104         ZFS_TIME_DECODE(&va.va_ctime, lr->lr_crtime);
105         va.va_nblocks = lr->lr_gen;
106
107         cn.cn_nameptr = name;
108         cn.cn_cred = kcred;
109         cn.cn_thread = curthread;
110         cn.cn_flags = SAVENAME;
111
112         vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY, curthread);
113         switch ((int)lr->lr_common.lrc_txtype) {
114         case TX_CREATE:
115                 error = VOP_CREATE(ZTOV(dzp), &vp, &cn, &va);
116                 break;
117         case TX_MKDIR:
118                 error = VOP_MKDIR(ZTOV(dzp), &vp, &cn, &va);
119                 break;
120         case TX_MKXATTR:
121                 error = zfs_make_xattrdir(dzp, &va, &vp, kcred);
122                 break;
123         case TX_SYMLINK:
124                 link = name + strlen(name) + 1;
125                 error = VOP_SYMLINK(ZTOV(dzp), &vp, &cn, &va, link);
126                 break;
127         default:
128                 error = ENOTSUP;
129         }
130         VOP_UNLOCK(ZTOV(dzp), 0, curthread);
131
132         if (error == 0 && vp != NULL) {
133                 VOP_UNLOCK(vp, 0, curthread);
134                 VN_RELE(vp);
135         }
136
137         VN_RELE(ZTOV(dzp));
138
139         return (error);
140 }
141
142 static int
143 zfs_replay_remove(zfsvfs_t *zfsvfs, lr_remove_t *lr, boolean_t byteswap)
144 {
145         char *name = (char *)(lr + 1);  /* name follows lr_remove_t */
146         znode_t *dzp;
147         struct componentname cn;
148         vnode_t *vp;
149         int error;
150
151         if (byteswap)
152                 byteswap_uint64_array(lr, sizeof (*lr));
153
154         if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
155                 return (error);
156
157         bzero(&cn, sizeof(cn));
158         cn.cn_nameptr = name;
159         cn.cn_namelen = strlen(name);
160         cn.cn_nameiop = DELETE;
161         cn.cn_flags = ISLASTCN | SAVENAME;
162         cn.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
163         cn.cn_cred = kcred;
164         cn.cn_thread = curthread;
165         vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY, curthread);
166         error = VOP_LOOKUP(ZTOV(dzp), &vp, &cn);
167         if (error != 0) {
168                 VOP_UNLOCK(ZTOV(dzp), 0, curthread);
169                 goto fail;
170         }
171
172         switch ((int)lr->lr_common.lrc_txtype) {
173         case TX_REMOVE:
174                 error = VOP_REMOVE(ZTOV(dzp), vp, &cn);
175                 break;
176         case TX_RMDIR:
177                 error = VOP_RMDIR(ZTOV(dzp), vp, &cn);
178                 break;
179         default:
180                 error = ENOTSUP;
181         }
182         vput(vp);
183         VOP_UNLOCK(ZTOV(dzp), 0, curthread);
184 fail:
185         VN_RELE(ZTOV(dzp));
186
187         return (error);
188 }
189
190 static int
191 zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
192 {
193         char *name = (char *)(lr + 1);  /* name follows lr_link_t */
194         znode_t *dzp, *zp;
195         struct componentname cn;
196         int error;
197
198         if (byteswap)
199                 byteswap_uint64_array(lr, sizeof (*lr));
200
201         if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
202                 return (error);
203
204         if ((error = zfs_zget(zfsvfs, lr->lr_link_obj, &zp)) != 0) {
205                 VN_RELE(ZTOV(dzp));
206                 return (error);
207         }
208
209         cn.cn_nameptr = name;
210         cn.cn_cred = kcred;
211         cn.cn_thread = curthread;
212         cn.cn_flags = SAVENAME;
213
214         vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY, curthread);
215         vn_lock(ZTOV(zp), LK_EXCLUSIVE | LK_RETRY, curthread);
216         error = VOP_LINK(ZTOV(dzp), ZTOV(zp), &cn);
217         VOP_UNLOCK(ZTOV(zp), 0, curthread);
218         VOP_UNLOCK(ZTOV(dzp), 0, curthread);
219
220         VN_RELE(ZTOV(zp));
221         VN_RELE(ZTOV(dzp));
222
223         return (error);
224 }
225
226 static int
227 zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, boolean_t byteswap)
228 {
229         char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */
230         char *tname = sname + strlen(sname) + 1;
231         znode_t *sdzp, *tdzp;
232         struct componentname scn, tcn;
233         vnode_t *svp, *tvp;
234         kthread_t *td = curthread;
235         int error;
236
237         if (byteswap)
238                 byteswap_uint64_array(lr, sizeof (*lr));
239
240         if ((error = zfs_zget(zfsvfs, lr->lr_sdoid, &sdzp)) != 0)
241                 return (error);
242
243         if ((error = zfs_zget(zfsvfs, lr->lr_tdoid, &tdzp)) != 0) {
244                 VN_RELE(ZTOV(sdzp));
245                 return (error);
246         }
247
248         svp = tvp = NULL;
249
250         bzero(&scn, sizeof(scn));
251         scn.cn_nameptr = sname;
252         scn.cn_namelen = strlen(sname);
253         scn.cn_nameiop = DELETE;
254         scn.cn_flags = ISLASTCN | SAVENAME;
255         scn.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
256         scn.cn_cred = kcred;
257         scn.cn_thread = td;
258         vn_lock(ZTOV(sdzp), LK_EXCLUSIVE | LK_RETRY, td);
259         error = VOP_LOOKUP(ZTOV(sdzp), &svp, &scn);
260         VOP_UNLOCK(ZTOV(sdzp), 0, td);
261         if (error != 0)
262                 goto fail;
263         VOP_UNLOCK(svp, 0, td);
264
265         bzero(&tcn, sizeof(tcn));
266         tcn.cn_nameptr = tname;
267         tcn.cn_namelen = strlen(tname);
268         tcn.cn_nameiop = RENAME;
269         tcn.cn_flags = ISLASTCN | SAVENAME;
270         tcn.cn_lkflags = LK_EXCLUSIVE | LK_RETRY;
271         tcn.cn_cred = kcred;
272         tcn.cn_thread = td;
273         vn_lock(ZTOV(tdzp), LK_EXCLUSIVE | LK_RETRY, td);
274         error = VOP_LOOKUP(ZTOV(tdzp), &tvp, &tcn);
275         if (error == EJUSTRETURN)
276                 tvp = NULL;
277         else if (error != 0) {
278                 VOP_UNLOCK(ZTOV(tdzp), 0, td);
279                 goto fail;
280         }
281
282         error = VOP_RENAME(ZTOV(sdzp), svp, &scn, ZTOV(tdzp), tvp, &tcn);
283         return (error);
284 fail:
285         if (svp != NULL)
286                 vrele(svp);
287         if (tvp != NULL)
288                 vrele(tvp);
289         VN_RELE(ZTOV(tdzp));
290         VN_RELE(ZTOV(sdzp));
291
292         return (error);
293 }
294
295 static int
296 zfs_replay_write(zfsvfs_t *zfsvfs, lr_write_t *lr, boolean_t byteswap)
297 {
298         char *data = (char *)(lr + 1);  /* data follows lr_write_t */
299         znode_t *zp;
300         int error;
301         ssize_t resid;
302
303         if (byteswap)
304                 byteswap_uint64_array(lr, sizeof (*lr));
305
306         if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
307                 /*
308                  * As we can log writes out of order, it's possible the
309                  * file has been removed. In this case just drop the write
310                  * and return success.
311                  */
312                 if (error == ENOENT)
313                         error = 0;
314                 return (error);
315         }
316
317         error = vn_rdwr(UIO_WRITE, ZTOV(zp), data, lr->lr_length,
318             lr->lr_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
319
320         VN_RELE(ZTOV(zp));
321
322         return (error);
323 }
324
325 static int
326 zfs_replay_truncate(zfsvfs_t *zfsvfs, lr_truncate_t *lr, boolean_t byteswap)
327 {
328
329         ZFS_LOG(0, "Unexpected code path, report to pjd@FreeBSD.org");
330         return (EOPNOTSUPP);
331 }
332
333 static int
334 zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap)
335 {
336         znode_t *zp;
337         vattr_t va;
338         vnode_t *vp;
339         int error;
340
341         if (byteswap)
342                 byteswap_uint64_array(lr, sizeof (*lr));
343
344         if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
345                 /*
346                  * As we can log setattrs out of order, it's possible the
347                  * file has been removed. In this case just drop the setattr
348                  * and return success.
349                  */
350                 if (error == ENOENT)
351                         error = 0;
352                 return (error);
353         }
354
355         zfs_init_vattr(&va, lr->lr_mask, lr->lr_mode,
356             lr->lr_uid, lr->lr_gid, 0, lr->lr_foid);
357
358         va.va_size = lr->lr_size;
359         ZFS_TIME_DECODE(&va.va_atime, lr->lr_atime);
360         ZFS_TIME_DECODE(&va.va_mtime, lr->lr_mtime);
361
362         vp = ZTOV(zp);
363         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
364         error = VOP_SETATTR(vp, &va, kcred, curthread);
365         VOP_UNLOCK(vp, 0, curthread);
366         VN_RELE(vp);
367
368         return (error);
369 }
370
371 static int
372 zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
373 {
374         ace_t *ace = (ace_t *)(lr + 1); /* ace array follows lr_acl_t */
375 #ifdef TODO
376         vsecattr_t vsa;
377 #endif
378         znode_t *zp;
379         int error;
380
381         if (byteswap) {
382                 byteswap_uint64_array(lr, sizeof (*lr));
383                 zfs_ace_byteswap(ace, lr->lr_aclcnt);
384         }
385
386         if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
387                 /*
388                  * As we can log acls out of order, it's possible the
389                  * file has been removed. In this case just drop the acl
390                  * and return success.
391                  */
392                 if (error == ENOENT)
393                         error = 0;
394                 return (error);
395         }
396
397 #ifdef TODO
398         bzero(&vsa, sizeof (vsa));
399         vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
400         vsa.vsa_aclcnt = lr->lr_aclcnt;
401         vsa.vsa_aclentp = ace;
402
403         error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred);
404 #else
405         error = EOPNOTSUPP;
406 #endif
407
408         VN_RELE(ZTOV(zp));
409
410         return (error);
411 }
412
413 /*
414  * Callback vectors for replaying records
415  */
416 zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE] = {
417         zfs_replay_error,       /* 0 no such transaction type */
418         zfs_replay_create,      /* TX_CREATE */
419         zfs_replay_create,      /* TX_MKDIR */
420         zfs_replay_create,      /* TX_MKXATTR */
421         zfs_replay_create,      /* TX_SYMLINK */
422         zfs_replay_remove,      /* TX_REMOVE */
423         zfs_replay_remove,      /* TX_RMDIR */
424         zfs_replay_link,        /* TX_LINK */
425         zfs_replay_rename,      /* TX_RENAME */
426         zfs_replay_write,       /* TX_WRITE */
427         zfs_replay_truncate,    /* TX_TRUNCATE */
428         zfs_replay_setattr,     /* TX_SETATTR */
429         zfs_replay_acl,         /* TX_ACL */
430 };