1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
3 *
4 * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
5 *
6 * This file is part of InterMezzo, http://www.inter-mezzo.org.
7 *
8 * InterMezzo is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
11 *
12 * InterMezzo is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with InterMezzo; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Reintegration of KML records
22 *
23 */
24
25 #define __NO_VERSION__
26 #include <linux/module.h>
27 #include <linux/errno.h>
28 #include <linux/fs.h>
29 #include <linux/kernel.h>
30 #include <linux/major.h>
31 #include <linux/slab.h>
32 #include <linux/vmalloc.h>
33 #include <linux/mm.h>
34 #include <asm/uaccess.h>
35 #include <asm/pgtable.h>
36 #include <asm/mmu_context.h>
37 #include <linux/intermezzo_fs.h>
38 #include <linux/intermezzo_psdev.h>
39
kmlreint_pre_secure(struct kml_rec * rec,struct file * dir,struct run_ctxt * saved)40 static void kmlreint_pre_secure(struct kml_rec *rec, struct file *dir,
41 struct run_ctxt *saved)
42 {
43 struct run_ctxt ctxt;
44 struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
45 int i;
46
47 ctxt.fsuid = rec->prefix.hdr->fsuid;
48 ctxt.fsgid = rec->prefix.hdr->fsgid;
49 ctxt.fs = KERNEL_DS;
50 ctxt.pwd = dd->dd_fset->fset_dentry;
51 ctxt.pwdmnt = dd->dd_fset->fset_mnt;
52
53 ctxt.root = ctxt.pwd;
54 ctxt.rootmnt = ctxt.pwdmnt;
55 if (rec->prefix.hdr->ngroups > 0) {
56 ctxt.ngroups = rec->prefix.hdr->ngroups;
57 for (i = 0; i< ctxt.ngroups; i++)
58 ctxt.groups[i] = rec->prefix.groups[i];
59 } else
60 ctxt.ngroups = 0;
61
62 push_ctxt(saved, &ctxt);
63 }
64
65
66 /* Append two strings in a less-retarded fashion. */
path_join(char * p1,int p1len,char * p2,int p2len)67 static char * path_join(char *p1, int p1len, char *p2, int p2len)
68 {
69 int size = p1len + p2len + 2; /* possibly one extra /, one NULL */
70 char *path;
71
72 path = kmalloc(size, GFP_KERNEL);
73 if (path == NULL)
74 return NULL;
75
76 memcpy(path, p1, p1len);
77 if (path[p1len - 1] != '/') {
78 path[p1len] = '/';
79 p1len++;
80 }
81 memcpy(path + p1len, p2, p2len);
82 path[p1len + p2len] = '\0';
83
84 return path;
85 }
86
kml_recno_equal(struct kml_rec * rec,struct presto_file_set * fset)87 static inline int kml_recno_equal(struct kml_rec *rec,
88 struct presto_file_set *fset)
89 {
90 return (rec->suffix->recno == fset->fset_lento_recno + 1);
91 }
92
version_equal(struct presto_version * a,struct inode * inode)93 static inline int version_equal(struct presto_version *a, struct inode *inode)
94 {
95 if (a == NULL)
96 return 1;
97
98 if (inode == NULL) {
99 CERROR("InterMezzo: NULL inode in version_equal()\n");
100 return 0;
101 }
102
103 if (inode->i_mtime == a->pv_mtime &&
104 (S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size))
105 return 1;
106
107 return 0;
108 }
109
reint_close(struct kml_rec * rec,struct file * file,struct lento_vfs_context * given_info)110 static int reint_close(struct kml_rec *rec, struct file *file,
111 struct lento_vfs_context *given_info)
112 {
113 struct run_ctxt saved_ctxt;
114 int error;
115 struct presto_file_set *fset;
116 struct lento_vfs_context info;
117 ENTRY;
118
119 memcpy(&info, given_info, sizeof(*given_info));
120
121
122 CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path);
123
124 fset = presto_fset(file->f_dentry);
125 if (fset->fset_flags & FSET_DATA_ON_DEMAND) {
126 struct iattr iattr;
127
128 iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE;
129 iattr.ia_mtime = (time_t)rec->new_objectv->pv_mtime;
130 iattr.ia_ctime = (time_t)rec->new_objectv->pv_ctime;
131 iattr.ia_size = (time_t)rec->new_objectv->pv_size;
132
133 /* no kml record, but update last rcvd */
134 /* save fileid in dentry for later backfetch */
135 info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID;
136 info.remote_ino = rec->ino;
137 info.remote_generation = rec->generation;
138 info.flags &= ~LENTO_FL_KML;
139 kmlreint_pre_secure(rec, file, &saved_ctxt);
140 error = lento_setattr(rec->path, &iattr, &info);
141 pop_ctxt(&saved_ctxt);
142
143 presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA;
144 } else {
145 int minor = presto_f2m(fset);
146
147 info.updated_time = rec->new_objectv->pv_mtime;
148 memcpy(&info.remote_version, rec->old_objectv,
149 sizeof(*rec->old_objectv));
150 info.remote_ino = rec->ino;
151 info.remote_generation = rec->generation;
152 error = izo_upc_backfetch(minor, rec->path, fset->fset_name,
153 &info);
154 if (error) {
155 CERROR("backfetch error %d\n", error);
156 /* if file doesn't exist anymore, then ignore the CLOSE
157 * and just update the last_rcvd.
158 */
159 if (error == ENOENT) {
160 CDEBUG(D_KML, "manually updating remote offset uuid %s"
161 "recno %d offset %Lu\n", info.uuid, info.recno, info.kml_offset);
162 error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
163 if(error)
164 CERROR("izo_rcvd_upd_remote error %d\n", error);
165
166 }
167 }
168
169 /* propagate error to avoid further reint */
170 }
171
172 EXIT;
173 return error;
174 }
175
reint_create(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)176 static int reint_create(struct kml_rec *rec, struct file *dir,
177 struct lento_vfs_context *info)
178 {
179 struct run_ctxt saved_ctxt;
180 int error; ENTRY;
181
182 CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path);
183 info->updated_time = rec->new_objectv->pv_ctime;
184 kmlreint_pre_secure(rec, dir, &saved_ctxt);
185 error = lento_create(rec->path, rec->mode, info);
186 pop_ctxt(&saved_ctxt);
187
188 EXIT;
189 return error;
190 }
191
reint_link(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)192 static int reint_link(struct kml_rec *rec, struct file *dir,
193 struct lento_vfs_context *info)
194 {
195 struct run_ctxt saved_ctxt;
196 int error;
197
198 ENTRY;
199
200 CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target);
201 info->updated_time = rec->new_objectv->pv_mtime;
202 kmlreint_pre_secure(rec, dir, &saved_ctxt);
203 error = lento_link(rec->path, rec->target, info);
204 pop_ctxt(&saved_ctxt);
205
206 EXIT;
207 return error;
208 }
209
reint_mkdir(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)210 static int reint_mkdir(struct kml_rec *rec, struct file *dir,
211 struct lento_vfs_context *info)
212 {
213 struct run_ctxt saved_ctxt;
214 int error;
215
216 ENTRY;
217
218 CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path);
219 info->updated_time = rec->new_objectv->pv_ctime;
220 kmlreint_pre_secure(rec, dir, &saved_ctxt);
221 error = lento_mkdir(rec->path, rec->mode, info);
222 pop_ctxt(&saved_ctxt);
223
224 EXIT;
225 return error;
226 }
227
reint_mknod(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)228 static int reint_mknod(struct kml_rec *rec, struct file *dir,
229 struct lento_vfs_context *info)
230 {
231 struct run_ctxt saved_ctxt;
232 int error, dev;
233
234 ENTRY;
235
236 CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path);
237 info->updated_time = rec->new_objectv->pv_ctime;
238 kmlreint_pre_secure(rec, dir, &saved_ctxt);
239
240 dev = rec->rdev ?: MKDEV(rec->major, rec->minor);
241
242 error = lento_mknod(rec->path, rec->mode, dev, info);
243 pop_ctxt(&saved_ctxt);
244
245 EXIT;
246 return error;
247 }
248
249
reint_noop(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)250 static int reint_noop(struct kml_rec *rec, struct file *dir,
251 struct lento_vfs_context *info)
252 {
253 return 0;
254 }
255
reint_rename(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)256 static int reint_rename(struct kml_rec *rec, struct file *dir,
257 struct lento_vfs_context *info)
258 {
259 struct run_ctxt saved_ctxt;
260 int error;
261
262 ENTRY;
263
264 CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target);
265 info->updated_time = rec->new_objectv->pv_mtime;
266 kmlreint_pre_secure(rec, dir, &saved_ctxt);
267 error = lento_rename(rec->path, rec->target, info);
268 pop_ctxt(&saved_ctxt);
269
270 EXIT;
271 return error;
272 }
273
reint_rmdir(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)274 static int reint_rmdir(struct kml_rec *rec, struct file *dir,
275 struct lento_vfs_context *info)
276 {
277 struct run_ctxt saved_ctxt;
278 int error;
279 char *path;
280
281 ENTRY;
282
283 path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
284 if (path == NULL) {
285 EXIT;
286 return -ENOMEM;
287 }
288
289 CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path);
290 info->updated_time = rec->new_parentv->pv_mtime;
291 kmlreint_pre_secure(rec, dir, &saved_ctxt);
292 error = lento_rmdir(path, info);
293 pop_ctxt(&saved_ctxt);
294
295 kfree(path);
296 EXIT;
297 return error;
298 }
299
reint_setattr(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)300 static int reint_setattr(struct kml_rec *rec, struct file *dir,
301 struct lento_vfs_context *info)
302 {
303 struct run_ctxt saved_ctxt;
304 struct iattr iattr;
305 int error;
306
307 ENTRY;
308
309 iattr.ia_valid = rec->valid;
310 iattr.ia_mode = (umode_t)rec->mode;
311 iattr.ia_uid = (uid_t)rec->uid;
312 iattr.ia_gid = (gid_t)rec->gid;
313 iattr.ia_size = (off_t)rec->size;
314 iattr.ia_ctime = (time_t)rec->ctime;
315 iattr.ia_mtime = (time_t)rec->mtime;
316 iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */
317 iattr.ia_attr_flags = rec->flags;
318
319 CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid);
320 kmlreint_pre_secure(rec, dir, &saved_ctxt);
321 error = lento_setattr(rec->path, &iattr, info);
322 pop_ctxt(&saved_ctxt);
323
324 EXIT;
325 return error;
326 }
327
reint_symlink(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)328 static int reint_symlink(struct kml_rec *rec, struct file *dir,
329 struct lento_vfs_context *info)
330 {
331 struct run_ctxt saved_ctxt;
332 int error;
333
334 ENTRY;
335
336 CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target);
337 info->updated_time = rec->new_objectv->pv_ctime;
338 kmlreint_pre_secure(rec, dir, &saved_ctxt);
339 error = lento_symlink(rec->target, rec->path, info);
340 pop_ctxt(&saved_ctxt);
341
342 EXIT;
343 return error;
344 }
345
reint_unlink(struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info)346 static int reint_unlink(struct kml_rec *rec, struct file *dir,
347 struct lento_vfs_context *info)
348 {
349 struct run_ctxt saved_ctxt;
350 int error;
351 char *path;
352
353 ENTRY;
354
355 path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
356 if (path == NULL) {
357 EXIT;
358 return -ENOMEM;
359 }
360
361 CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path);
362 info->updated_time = rec->new_parentv->pv_mtime;
363 kmlreint_pre_secure(rec, dir, &saved_ctxt);
364 error = lento_unlink(path, info);
365 pop_ctxt(&saved_ctxt);
366
367 kfree(path);
368 EXIT;
369 return error;
370 }
371
branch_reint_rename(struct presto_file_set * fset,struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info,char * kml_data,__u64 kml_size)372 static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec,
373 struct file *dir, struct lento_vfs_context *info,
374 char * kml_data, __u64 kml_size)
375 {
376 int error;
377
378 ENTRY;
379
380 error = reint_rename(rec, dir, info);
381 if (error == -ENOENT) {
382 /* normal reint failed because path was not found */
383 struct rec_info rec;
384
385 CDEBUG(D_KML, "saving branch rename kml\n");
386 rec.is_kml = 1;
387 rec.size = kml_size;
388 error = presto_log(fset, &rec, kml_data, kml_size,
389 NULL, 0, NULL, 0, NULL, 0);
390 if (error == 0)
391 error = presto_write_last_rcvd(&rec, fset, info);
392 }
393
394 EXIT;
395 return error;
396 }
397
branch_reinter(struct presto_file_set * fset,struct kml_rec * rec,struct file * dir,struct lento_vfs_context * info,char * kml_data,__u64 kml_size)398 int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec,
399 struct file *dir, struct lento_vfs_context *info,
400 char * kml_data, __u64 kml_size)
401 {
402 int error = 0;
403 int op = rec->prefix.hdr->opcode;
404
405 if (op == KML_OPCODE_CLOSE) {
406 /* regular close and backfetch */
407 error = reint_close(rec, dir, info);
408 } else if (op == KML_OPCODE_RENAME) {
409 /* rename only if name already exists */
410 error = branch_reint_rename(fset, rec, dir, info,
411 kml_data, kml_size);
412 } else {
413 /* just rewrite kml into branch/kml and update last_rcvd */
414 struct rec_info rec;
415
416 CDEBUG(D_KML, "Saving branch kml\n");
417 rec.is_kml = 1;
418 rec.size = kml_size;
419 error = presto_log(fset, &rec, kml_data, kml_size,
420 NULL, 0, NULL, 0, NULL, 0);
421 if (error == 0)
422 error = presto_write_last_rcvd(&rec, fset, info);
423 }
424
425 return error;
426 }
427
428 typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir,
429 struct lento_vfs_context *info);
430
431 static reinter_t presto_reinters[KML_OPCODE_NUM] =
432 {
433 [KML_OPCODE_CLOSE] = reint_close,
434 [KML_OPCODE_CREATE] = reint_create,
435 [KML_OPCODE_LINK] = reint_link,
436 [KML_OPCODE_MKDIR] = reint_mkdir,
437 [KML_OPCODE_MKNOD] = reint_mknod,
438 [KML_OPCODE_NOOP] = reint_noop,
439 [KML_OPCODE_RENAME] = reint_rename,
440 [KML_OPCODE_RMDIR] = reint_rmdir,
441 [KML_OPCODE_SETATTR] = reint_setattr,
442 [KML_OPCODE_SYMLINK] = reint_symlink,
443 [KML_OPCODE_UNLINK] = reint_unlink,
444 };
445
get_reinter(int op)446 static inline reinter_t get_reinter(int op)
447 {
448 if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t))
449 return NULL;
450 else
451 return presto_reinters[op];
452 }
453
kml_reint_rec(struct file * dir,struct izo_ioctl_data * data)454 int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data)
455 {
456 char *ptr;
457 char *end;
458 struct kml_rec rec;
459 int error = 0;
460 struct lento_vfs_context info;
461 struct presto_cache *cache;
462 struct presto_file_set *fset;
463 struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
464 int op;
465 reinter_t reinter;
466
467 struct izo_rcvd_rec lr_rec;
468 int off;
469
470 ENTRY;
471
472 error = presto_prep(dir->f_dentry, &cache, &fset);
473 if ( error ) {
474 CERROR("intermezzo: Reintegration on invalid file\n");
475 return error;
476 }
477
478 if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) {
479 CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
480 dir->f_dentry->d_inode->i_ino);
481
482 return -EINVAL;
483 }
484
485 if (data->ioc_plen1 > 64 * 1024) {
486 EXIT;
487 return -ENOSPC;
488 }
489
490 ptr = fset->fset_reint_buf;
491 end = ptr + data->ioc_plen1;
492
493 if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) {
494 EXIT;
495 error = -EFAULT;
496 goto out;
497 }
498
499 error = kml_unpack(&rec, &ptr, end);
500 if (error) {
501 EXIT;
502 error = -EFAULT;
503 goto out;
504 }
505
506 off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid);
507 if (off < 0) {
508 CERROR("No last_rcvd record, setting to 0\n");
509 memset(&lr_rec, 0, sizeof(lr_rec));
510 }
511
512 data->ioc_kmlsize = ptr - fset->fset_reint_buf;
513
514 if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
515 CERROR("KML record number %Lu expected, not %d\n",
516 lr_rec.lr_remote_recno + 1,
517 rec.suffix->recno);
518
519 #if 0
520 if (!version_check(&rec, dd->dd_fset, &info)) {
521 /* FIXME: do an upcall to resolve conflicts */
522 CERROR("intermezzo: would be a conflict!\n");
523 error = -EINVAL;
524 EXIT;
525 goto out;
526 }
527 #endif
528 }
529
530 op = rec.prefix.hdr->opcode;
531
532 reinter = get_reinter(op);
533 if (!reinter) {
534 CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op);
535 error = -EINVAL;
536 EXIT;
537 goto out;
538 }
539
540 info.kml_offset = data->ioc_offset + data->ioc_kmlsize;
541 info.recno = rec.suffix->recno;
542 info.flags = LENTO_FL_EXPECT;
543 if (data->ioc_flags)
544 info.flags |= LENTO_FL_KML;
545
546 memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid));
547
548 if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags)
549 error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf,
550 data->ioc_kmlsize);
551 else
552 error = reinter(&rec, dir, &info);
553 out:
554 EXIT;
555 return error;
556 }
557
izo_get_fileid(struct file * dir,struct izo_ioctl_data * data)558 int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data)
559 {
560 char *buf = NULL;
561 char *ptr;
562 char *end;
563 struct kml_rec rec;
564 struct file *file;
565 struct presto_cache *cache;
566 struct presto_file_set *fset;
567 struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
568 struct run_ctxt saved_ctxt;
569 int error;
570
571 ENTRY;
572
573 error = presto_prep(dir->f_dentry, &cache, &fset);
574 if ( error ) {
575 CERROR("intermezzo: Reintegration on invalid file\n");
576 return error;
577 }
578
579 if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) {
580 CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
581 dir->f_dentry->d_inode->i_ino);
582
583 return -EINVAL;
584 }
585
586
587 PRESTO_ALLOC(buf, data->ioc_plen1);
588 if (!buf) {
589 EXIT;
590 return -ENOMEM;
591 }
592 ptr = buf;
593 end = buf + data->ioc_plen1;
594
595 if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) {
596 EXIT;
597 PRESTO_FREE(buf, data->ioc_plen1);
598 return -EFAULT;
599 }
600
601 error = kml_unpack(&rec, &ptr, end);
602 if (error) {
603 EXIT;
604 PRESTO_FREE(buf, data->ioc_plen1);
605 return -EFAULT;
606 }
607
608 kmlreint_pre_secure(&rec, dir, &saved_ctxt);
609
610 file = filp_open(rec.path, O_RDONLY, 0);
611 if (!file || IS_ERR(file)) {
612 error = PTR_ERR(file);
613 goto out;
614 }
615 data->ioc_ino = file->f_dentry->d_inode->i_ino;
616 data->ioc_generation = file->f_dentry->d_inode->i_generation;
617 filp_close(file, 0);
618
619 CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path,
620 data->ioc_ino, data->ioc_generation);
621
622 out:
623 if (buf)
624 PRESTO_FREE(buf, data->ioc_plen1);
625 pop_ctxt(&saved_ctxt);
626 EXIT;
627 return error;
628 }
629
630
631