Mercurial > illumos > onarm
comparison usr/src/cmd/fs.d/cachefs/fsck/dlog_ck.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c9caec207d52 |
---|---|
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, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* | |
23 * Copyright 1996-2002 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
27 #pragma ident "@(#)dlog_ck.c 1.13 05/06/08 SMI" | |
28 | |
29 #include <sys/types.h> | |
30 #include <stdio.h> | |
31 #include <stddef.h> | |
32 #include <sys/param.h> | |
33 #include <sys/stat.h> | |
34 #include <fcntl.h> | |
35 #include <unistd.h> | |
36 #include <errno.h> | |
37 | |
38 #include <sys/fs/cachefs_fs.h> | |
39 #include <sys/fs/cachefs_dlog.h> | |
40 | |
41 /* forward references */ | |
42 static int create_mapfile(char *fname, int size); | |
43 | |
44 int | |
45 dlog_ck(char *dir_path, ino64_t *maxlocalfilenop) | |
46 { | |
47 int err; | |
48 int n; | |
49 char dlog_path[MAXPATHLEN]; | |
50 char dmap_path[MAXPATHLEN]; | |
51 struct stat64 statinfo; | |
52 int fd; | |
53 int dlog_version; | |
54 off_t offset; | |
55 struct cfs_dlog_entry buf; | |
56 int max_seq_num; | |
57 int ent_count = 0; | |
58 ino64_t fileno, maxlocalfileno; | |
59 | |
60 if (maxlocalfilenop) | |
61 *maxlocalfilenop = 0LL; | |
62 | |
63 n = strlen(dir_path) + strlen(CACHEFS_DLOG_FILE) + 2; | |
64 if (n > MAXPATHLEN) { | |
65 pr_err(gettext("%s/%s: path too long"), | |
66 dir_path, CACHEFS_DLOG_FILE); | |
67 return (-1); | |
68 } | |
69 sprintf(dlog_path, "%s/%s", dir_path, CACHEFS_DLOG_FILE); | |
70 | |
71 n = strlen(dir_path) + strlen(CACHEFS_DMAP_FILE) + 2; | |
72 if (n > MAXPATHLEN) { | |
73 pr_err(gettext("%s/%s: path too long"), | |
74 dir_path, CACHEFS_DMAP_FILE); | |
75 return (-1); | |
76 } | |
77 sprintf(dmap_path, "%s/%s", dir_path, CACHEFS_DMAP_FILE); | |
78 | |
79 err = lstat64(dlog_path, &statinfo); | |
80 if (err < 0) { | |
81 if (errno == ENOENT) | |
82 (void) unlink(dmap_path); | |
83 /* | |
84 * No disconnect log(dlog) file exists to check | |
85 */ | |
86 return (0); | |
87 } | |
88 | |
89 /* this file will be <2GB */ | |
90 fd = open(dlog_path, O_RDWR); | |
91 if (fd < 0) { | |
92 pr_err(gettext("can't open %s"), dlog_path); | |
93 return (-2); | |
94 } | |
95 err = read(fd, &dlog_version, sizeof (dlog_version)); | |
96 if (err != sizeof (dlog_version)) { | |
97 pr_err(gettext("can't read %s"), dlog_path); | |
98 (void) close(fd); | |
99 return (-3); | |
100 } | |
101 if (dlog_version != CFS_DLOG_VERSION) { | |
102 pr_err(gettext( | |
103 "unknown version number in %s"), dlog_path); | |
104 (void) close(fd); | |
105 return (-4); | |
106 } | |
107 | |
108 offset = sizeof (dlog_version); | |
109 max_seq_num = 0; | |
110 maxlocalfileno = 0LL; | |
111 while (offset < (off_t)statinfo.st_size) { | |
112 err = (int) lseek(fd, offset, SEEK_SET); | |
113 if (err == -1) { | |
114 pr_err(gettext("can't lseek %s"), dlog_path); | |
115 (void) close(fd); | |
116 return (-5); | |
117 } | |
118 | |
119 err = read(fd, &buf, sizeof (buf)); | |
120 if (err < 0) { | |
121 pr_err(gettext("can't read %s"), dlog_path); | |
122 (void) close(fd); | |
123 return (-6); | |
124 } | |
125 ++ent_count; | |
126 if (buf.dl_op == CFS_DLOG_TRAILER) { | |
127 goto out; | |
128 } | |
129 if ((buf.dl_len & 3) == 0) { | |
130 /* | |
131 * Record length must be on a word boundary and | |
132 * fit into the correct size range. | |
133 */ | |
134 if ((buf.dl_len < sizeof (int)) || | |
135 (buf.dl_len > CFS_DLOG_ENTRY_MAXSIZE)) { | |
136 goto out; | |
137 } | |
138 /* | |
139 * Make sure length does not point beyond end of | |
140 * file | |
141 */ | |
142 if ((offset + (off_t)buf.dl_len) > | |
143 (off_t)statinfo.st_size) { | |
144 goto out; | |
145 } | |
146 } else { | |
147 goto out; | |
148 } | |
149 | |
150 /* make sure the valid field is reasonable */ | |
151 switch (buf.dl_valid) { | |
152 case CFS_DLOG_VAL_CRASH: | |
153 case CFS_DLOG_VAL_COMMITTED: | |
154 case CFS_DLOG_VAL_ERROR: | |
155 case CFS_DLOG_VAL_PROCESSED: | |
156 break; | |
157 default: | |
158 goto out; | |
159 } | |
160 | |
161 /* make sure the operation field is reasonable */ | |
162 fileno = 0LL; | |
163 switch (buf.dl_op) { | |
164 case CFS_DLOG_CREATE: | |
165 fileno = buf.dl_u.dl_create.dl_new_cid.cid_fileno; | |
166 break; | |
167 case CFS_DLOG_REMOVE: | |
168 break; | |
169 case CFS_DLOG_LINK: | |
170 break; | |
171 case CFS_DLOG_RENAME: | |
172 break; | |
173 case CFS_DLOG_MKDIR: | |
174 fileno = buf.dl_u.dl_mkdir.dl_child_cid.cid_fileno; | |
175 break; | |
176 case CFS_DLOG_RMDIR: | |
177 break; | |
178 case CFS_DLOG_SYMLINK: | |
179 fileno = buf.dl_u.dl_symlink.dl_child_cid.cid_fileno; | |
180 break; | |
181 case CFS_DLOG_SETATTR: | |
182 break; | |
183 case CFS_DLOG_SETSECATTR: | |
184 break; | |
185 case CFS_DLOG_MODIFIED: | |
186 break; | |
187 case CFS_DLOG_MAPFID: | |
188 break; | |
189 default: | |
190 goto out; | |
191 } | |
192 | |
193 /* track the largest local fileno used */ | |
194 if (maxlocalfileno < fileno) | |
195 maxlocalfileno = fileno; | |
196 | |
197 /* track the largest sequence number used */ | |
198 if (max_seq_num < buf.dl_seq) { | |
199 max_seq_num = buf.dl_seq; | |
200 } | |
201 | |
202 offset += buf.dl_len; | |
203 } | |
204 | |
205 out: | |
206 if ((buf.dl_op != CFS_DLOG_TRAILER) || | |
207 (buf.dl_len != sizeof (struct cfs_dlog_trailer)) || | |
208 (buf.dl_valid != CFS_DLOG_VAL_COMMITTED) || | |
209 ((offset + (off_t)buf.dl_len) != (off_t)statinfo.st_size)) { | |
210 ftruncate(fd, offset); | |
211 buf.dl_len = sizeof (struct cfs_dlog_trailer); | |
212 buf.dl_op = CFS_DLOG_TRAILER; | |
213 buf.dl_valid = CFS_DLOG_VAL_COMMITTED; | |
214 buf.dl_seq = max_seq_num + 1; | |
215 if (wrdlog(fd, &buf, buf.dl_len, offset) != 0) { | |
216 (void) close(fd); | |
217 return (-7); | |
218 } | |
219 } | |
220 | |
221 if (fsync(fd) == -1) { | |
222 pr_err(gettext("Cannot sync %s"), dlog_path); | |
223 (void) close(fd); | |
224 return (-8); | |
225 } | |
226 (void) close(fd); /* ignore return since fsync() successful */ | |
227 | |
228 /* check to see that mapfile exists; if not, create it. */ | |
229 if (access(dmap_path, F_OK) != 0) { | |
230 /* XXX ent_count is a very high upper bound */ | |
231 if (create_mapfile(dmap_path, | |
232 ent_count * sizeof (struct cfs_dlog_mapping_space)) != 0) { | |
233 return (-9); | |
234 } | |
235 } | |
236 | |
237 if (maxlocalfilenop) | |
238 *maxlocalfilenop = maxlocalfileno; | |
239 return (0); | |
240 } | |
241 | |
242 int | |
243 wrdlog(int fd, char * buf, int len, off_t offset) | |
244 { | |
245 int err; | |
246 | |
247 err = lseek(fd, offset, SEEK_SET); | |
248 if (err < 0) { | |
249 return (-1); | |
250 } | |
251 | |
252 err = write(fd, buf, len); | |
253 if (err != len) { | |
254 return (-2); | |
255 } | |
256 | |
257 return (0); | |
258 } | |
259 | |
260 static int | |
261 create_mapfile(char *fname, int size) | |
262 { | |
263 char buffy[BUFSIZ]; | |
264 int fd, rc, wsize; | |
265 | |
266 /* this file will be <2GB */ | |
267 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); | |
268 if (fd < 0) | |
269 return (errno); | |
270 | |
271 memset(buffy, '\0', sizeof (buffy)); | |
272 while (size > 0) { | |
273 wsize = (size > sizeof (buffy)) ? sizeof (buffy) : size; | |
274 if (write(fd, buffy, wsize) != wsize) { | |
275 rc = errno; | |
276 (void) close(fd); | |
277 (void) unlink(fname); | |
278 return (rc); | |
279 } | |
280 size -= wsize; | |
281 } | |
282 | |
283 if (fsync(fd) != 0) { | |
284 rc = errno; | |
285 (void) close(fd); | |
286 (void) unlink(fname); | |
287 return (rc); | |
288 } | |
289 (void) close(fd); | |
290 | |
291 return (0); | |
292 } |