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