This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / fs / intermezzo / kml_reint.c
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 #include <linux/module.h>
26 #include <linux/errno.h>
27 #include <linux/fs.h>
28 #include <linux/kernel.h>
29 #include <linux/major.h>
30 #include <linux/slab.h>
31 #include <linux/vmalloc.h>
32 #include <linux/mm.h>
33 #include <asm/uaccess.h>
34 #include <asm/pgtable.h>
35 #include <asm/mmu_context.h>
36
37 #include "intermezzo_fs.h"
38 #include "intermezzo_psdev.h"
39
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.group_info = groups_alloc(rec->prefix.hdr->ngroups);
57                 for (i = 0; i< ctxt.group_info->ngroups; i++) 
58                         GROUP_AT(ctxt.group_info,i)= rec->prefix.groups[i];
59         } else
60                 ctxt.group_info = groups_alloc(0);
61
62         push_ctxt(saved, &ctxt);
63 }
64
65
66 /* Append two strings in a less-retarded fashion. */
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
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
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.tv_sec == a->pv_mtime_sec &&
104             inode->i_mtime.tv_nsec == a->pv_mtime_nsec &&
105             (S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size))
106                 return 1;
107
108         return 0;
109 }
110
111 static int reint_close(struct kml_rec *rec, struct file *file,
112                        struct lento_vfs_context *given_info)
113 {
114         struct run_ctxt saved_ctxt;
115         int error;
116         struct presto_file_set *fset;
117         struct lento_vfs_context info; 
118         ENTRY;
119
120         memcpy(&info, given_info, sizeof(*given_info));
121
122
123         CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path);
124
125         fset = presto_fset(file->f_dentry);
126         if (fset->fset_flags & FSET_DATA_ON_DEMAND) {
127                 struct iattr iattr;
128
129                 iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE;
130                 iattr.ia_mtime.tv_sec = (time_t)rec->new_objectv->pv_mtime_sec;
131                 iattr.ia_mtime.tv_nsec = (time_t)rec->new_objectv->pv_mtime_nsec;
132                 iattr.ia_ctime.tv_sec = (time_t)rec->new_objectv->pv_ctime_sec;
133                 iattr.ia_ctime.tv_nsec = (time_t)rec->new_objectv->pv_ctime_nsec;
134                 iattr.ia_size = (time_t)rec->new_objectv->pv_size;
135
136                 /* no kml record, but update last rcvd */
137                 /* save fileid in dentry for later backfetch */
138                 info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID;
139                 info.remote_ino = rec->ino;
140                 info.remote_generation = rec->generation;
141                 info.flags &= ~LENTO_FL_KML;
142                 kmlreint_pre_secure(rec, file, &saved_ctxt);
143                 error = lento_setattr(rec->path, &iattr, &info);
144                 pop_ctxt(&saved_ctxt);
145
146                 presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA;
147         } else {
148                 int minor = presto_f2m(fset);
149
150                 info.updated_time.tv_sec = rec->new_objectv->pv_mtime_sec;
151                 info.updated_time.tv_nsec = rec->new_objectv->pv_mtime_nsec;
152                 memcpy(&info.remote_version, rec->old_objectv, 
153                        sizeof(*rec->old_objectv));
154                 info.remote_ino = rec->ino;
155                 info.remote_generation = rec->generation;
156                 error = izo_upc_backfetch(minor, rec->path, fset->fset_name,
157                                           &info);
158                 if (error) {
159                         CERROR("backfetch error %d\n", error);
160                         /* if file doesn't exist anymore,  then ignore the CLOSE
161                          * and just update the last_rcvd.
162                          */
163                         if (error == ENOENT) {
164                                 CDEBUG(D_KML, "manually updating remote offset uuid %s"
165                                        "recno %d offset %Lu\n", info.uuid, info.recno,
166                                        (unsigned long long) info.kml_offset);
167                                 error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
168                                 if(error)
169                                         CERROR("izo_rcvd_upd_remote error %d\n", error);
170
171                         } 
172                 }
173                         
174                 /* propagate error to avoid further reint */
175         }
176
177         EXIT;
178         return error;
179 }
180
181 static int reint_create(struct kml_rec *rec, struct file *dir,
182                         struct lento_vfs_context *info)
183 {
184         struct run_ctxt saved_ctxt;
185         int     error;        ENTRY;
186
187         CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path);
188         info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec;
189         info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec;
190         kmlreint_pre_secure(rec, dir, &saved_ctxt);
191         error = lento_create(rec->path, rec->mode, info);
192         pop_ctxt(&saved_ctxt); 
193
194         EXIT;
195         return error;
196 }
197
198 static int reint_link(struct kml_rec *rec, struct file *dir,
199                       struct lento_vfs_context *info)
200 {
201         struct run_ctxt saved_ctxt;
202         int     error;
203
204         ENTRY;
205
206         CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target);
207         info->updated_time.tv_sec = rec->new_objectv->pv_mtime_sec;
208         info->updated_time.tv_nsec = rec->new_objectv->pv_mtime_nsec;
209         kmlreint_pre_secure(rec, dir, &saved_ctxt);
210         error = lento_link(rec->path, rec->target, info);
211         pop_ctxt(&saved_ctxt); 
212
213         EXIT;
214         return error;
215 }
216
217 static int reint_mkdir(struct kml_rec *rec, struct file *dir,
218                        struct lento_vfs_context *info)
219 {
220         struct run_ctxt saved_ctxt;
221         int     error;
222
223         ENTRY;
224
225         CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path);
226         info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec;
227         info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec;
228         kmlreint_pre_secure(rec, dir, &saved_ctxt);
229         error = lento_mkdir(rec->path, rec->mode, info);
230         pop_ctxt(&saved_ctxt); 
231
232         EXIT;
233         return error;
234 }
235
236 static int reint_mknod(struct kml_rec *rec, struct file *dir,
237                        struct lento_vfs_context *info)
238 {
239         struct run_ctxt saved_ctxt;
240         int     error;
241         dev_t dev;
242
243         ENTRY;
244
245         CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path);
246         info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec;
247         info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec;
248         kmlreint_pre_secure(rec, dir, &saved_ctxt);
249
250         dev = rec->rdev ? old_decode_dev(rec->rdev) : MKDEV(rec->major, rec->minor);
251
252         error = lento_mknod(rec->path, rec->mode, dev, info);
253         pop_ctxt(&saved_ctxt); 
254
255         EXIT;
256         return error;
257 }
258
259
260 static int reint_noop(struct kml_rec *rec, struct file *dir,
261                       struct lento_vfs_context *info)
262 {
263         return 0;
264 }
265
266 static int reint_rename(struct kml_rec *rec, struct file *dir,
267                         struct lento_vfs_context *info)
268 {
269         struct run_ctxt saved_ctxt;
270         int     error;
271
272         ENTRY;
273
274         CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target);
275         info->updated_time.tv_sec = rec->new_objectv->pv_mtime_sec;
276         info->updated_time.tv_nsec = rec->new_objectv->pv_mtime_nsec;
277         kmlreint_pre_secure(rec, dir, &saved_ctxt);
278         error = lento_rename(rec->path, rec->target, info);
279         pop_ctxt(&saved_ctxt); 
280
281         EXIT;
282         return error;
283 }
284
285 static int reint_rmdir(struct kml_rec *rec, struct file *dir,
286                        struct lento_vfs_context *info)
287 {
288         struct run_ctxt saved_ctxt;
289         int     error;
290         char *path;
291
292         ENTRY;
293
294         path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
295         if (path == NULL) {
296                 EXIT;
297                 return -ENOMEM;
298         }
299
300         CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path);
301         info->updated_time.tv_sec = rec->new_parentv->pv_mtime_sec;
302         info->updated_time.tv_nsec = rec->new_parentv->pv_mtime_nsec;
303         kmlreint_pre_secure(rec, dir, &saved_ctxt);
304         error = lento_rmdir(path, info);
305         pop_ctxt(&saved_ctxt); 
306
307         kfree(path);
308         EXIT;
309         return error;
310 }
311
312 static int reint_setattr(struct kml_rec *rec, struct file *dir,
313                          struct lento_vfs_context *info)
314 {
315         struct run_ctxt saved_ctxt;
316         struct iattr iattr;
317         int     error;
318
319         ENTRY;
320
321         iattr.ia_valid = rec->valid;
322         iattr.ia_mode  = (umode_t)rec->mode;
323         iattr.ia_uid   = (uid_t)rec->uid;
324         iattr.ia_gid   = (gid_t)rec->gid;
325         iattr.ia_size  = (off_t)rec->size;
326         iattr.ia_ctime.tv_sec = rec->ctime_sec;
327         iattr.ia_ctime.tv_nsec = rec->ctime_nsec;
328         iattr.ia_mtime.tv_sec = rec->mtime_sec;
329         iattr.ia_mtime.tv_nsec = rec->mtime_nsec;
330         iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */
331         iattr.ia_attr_flags = rec->flags;
332
333         CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid);
334         kmlreint_pre_secure(rec, dir, &saved_ctxt);
335         error = lento_setattr(rec->path, &iattr, info);
336         pop_ctxt(&saved_ctxt); 
337
338         EXIT;
339         return error;
340 }
341
342 static int reint_symlink(struct kml_rec *rec, struct file *dir,
343                          struct lento_vfs_context *info)
344 {
345         struct run_ctxt saved_ctxt;
346         int     error;
347
348         ENTRY;
349
350         CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target);
351         info->updated_time.tv_sec = rec->new_objectv->pv_ctime_sec;
352         info->updated_time.tv_nsec = rec->new_objectv->pv_ctime_nsec;
353         kmlreint_pre_secure(rec, dir, &saved_ctxt);
354         error = lento_symlink(rec->target, rec->path, info);
355         pop_ctxt(&saved_ctxt); 
356
357         EXIT;
358         return error;
359 }
360
361 static int reint_unlink(struct kml_rec *rec, struct file *dir,
362                         struct lento_vfs_context *info)
363 {
364         struct run_ctxt saved_ctxt;
365         int     error;
366         char *path;
367
368         ENTRY;
369
370         path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
371         if (path == NULL) {
372                 EXIT;
373                 return -ENOMEM;
374         }
375
376         CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path);
377         info->updated_time.tv_sec = rec->new_parentv->pv_mtime_sec;
378         info->updated_time.tv_nsec = rec->new_parentv->pv_mtime_nsec;
379         kmlreint_pre_secure(rec, dir, &saved_ctxt);
380         error = lento_unlink(path, info);
381         pop_ctxt(&saved_ctxt); 
382
383         kfree(path);
384         EXIT;
385         return error;
386 }
387
388 static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec, 
389                    struct file *dir, struct lento_vfs_context *info,
390                    char * kml_data, __u64 kml_size)
391 {
392         int     error;
393
394         ENTRY;
395
396         error = reint_rename(rec, dir, info);
397         if (error == -ENOENT) {
398                 /* normal reint failed because path was not found */
399                 struct rec_info rec;
400                 
401                 CDEBUG(D_KML, "saving branch rename kml\n");
402                 rec.is_kml = 1;
403                 rec.size = kml_size;
404                 error = presto_log(fset, &rec, kml_data, kml_size,
405                            NULL, 0, NULL, 0,  NULL, 0);
406                 if (error == 0)
407                         error = presto_write_last_rcvd(&rec, fset, info);
408         }
409
410         EXIT;
411         return error;
412 }
413
414 int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec, 
415                    struct file *dir, struct lento_vfs_context *info,
416                    char * kml_data, __u64 kml_size)
417 {
418         int error = 0;
419         int op = rec->prefix.hdr->opcode;
420
421         if (op == KML_OPCODE_CLOSE) {
422                 /* regular close and backfetch */
423                 error = reint_close(rec, dir, info);
424         } else if  (op == KML_OPCODE_RENAME) {
425                 /* rename only if name already exists  */
426                 error = branch_reint_rename(fset, rec, dir, info,
427                                             kml_data, kml_size);
428         } else {
429                 /* just rewrite kml into branch/kml and update last_rcvd */
430                 struct rec_info rec;
431                 
432                 CDEBUG(D_KML, "Saving branch kml\n");
433                 rec.is_kml = 1;
434                 rec.size = kml_size;
435                 error = presto_log(fset, &rec, kml_data, kml_size,
436                            NULL, 0, NULL, 0,  NULL, 0);
437                 if (error == 0)
438                         error = presto_write_last_rcvd(&rec, fset, info);
439         }
440                 
441         return error;
442 }
443
444 typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir,
445                          struct lento_vfs_context *info);
446
447 static reinter_t presto_reinters[KML_OPCODE_NUM] =
448 {
449         [KML_OPCODE_CLOSE] = reint_close,
450         [KML_OPCODE_CREATE] = reint_create,
451         [KML_OPCODE_LINK] = reint_link,
452         [KML_OPCODE_MKDIR] = reint_mkdir,
453         [KML_OPCODE_MKNOD] = reint_mknod,
454         [KML_OPCODE_NOOP] = reint_noop,
455         [KML_OPCODE_RENAME] = reint_rename,
456         [KML_OPCODE_RMDIR] = reint_rmdir,
457         [KML_OPCODE_SETATTR] = reint_setattr,
458         [KML_OPCODE_SYMLINK] = reint_symlink,
459         [KML_OPCODE_UNLINK] = reint_unlink,
460 };
461
462 static inline reinter_t get_reinter(int op)
463 {
464         if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t)) 
465                 return NULL; 
466         else 
467                 return  presto_reinters[op];
468 }
469
470 int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data)
471 {
472         char *ptr;
473         char *end;
474         struct kml_rec rec;
475         int error = 0;
476         struct lento_vfs_context info;
477         struct presto_cache *cache;
478         struct presto_file_set *fset;
479         struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
480         int op;
481         reinter_t reinter;
482
483         struct izo_rcvd_rec lr_rec;
484         int off;
485
486         ENTRY;
487
488         error = presto_prep(dir->f_dentry, &cache, &fset);
489         if ( error  ) {
490                 CERROR("intermezzo: Reintegration on invalid file\n");
491                 return error;
492         }
493
494         if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
495                 CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
496                        dir->f_dentry->d_inode->i_ino);
497                     
498                 return -EINVAL;
499         }
500
501         if (data->ioc_plen1 > 64 * 1024) {
502                 EXIT;
503                 return -ENOSPC;
504         }
505
506         ptr = fset->fset_reint_buf;
507         end = ptr + data->ioc_plen1;
508
509         if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) { 
510                 EXIT;
511                 error = -EFAULT;
512                 goto out;
513         }
514
515         error = kml_unpack(&rec, &ptr, end);
516         if (error) { 
517                 EXIT;
518                 error = -EFAULT;
519                 goto out;
520         }
521
522         off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid);
523         if (off < 0) {
524                 CERROR("No last_rcvd record, setting to 0\n");
525                 memset(&lr_rec, 0, sizeof(lr_rec));
526         }
527  
528         data->ioc_kmlsize = ptr - fset->fset_reint_buf;
529
530         if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
531                 CERROR("KML record number %Lu expected, not %d\n",
532                        (unsigned long long) (lr_rec.lr_remote_recno + 1),
533                        rec.suffix->recno);
534
535 #if 0
536                 if (!version_check(&rec, dd->dd_fset, &info)) {
537                         /* FIXME: do an upcall to resolve conflicts */
538                         CERROR("intermezzo: would be a conflict!\n");
539                         error = -EINVAL;
540                         EXIT;
541                         goto out;
542                 }
543 #endif
544         }
545
546         op = rec.prefix.hdr->opcode;
547
548         reinter = get_reinter(op);
549         if (!reinter) { 
550                 CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op);
551                 error = -EINVAL;
552                 EXIT;
553                 goto out;
554         }
555
556         info.kml_offset = data->ioc_offset + data->ioc_kmlsize;
557         info.recno = rec.suffix->recno;
558         info.flags = LENTO_FL_EXPECT;
559         if (data->ioc_flags)
560                 info.flags |= LENTO_FL_KML;
561
562         memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid));
563
564         if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags)
565                 error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf,
566                                        data->ioc_kmlsize);
567         else 
568                 error = reinter(&rec, dir, &info);
569  out: 
570         EXIT;
571         return error;
572 }
573
574 int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data)
575 {
576         char *buf = NULL; 
577         char *ptr;
578         char *end;
579         struct kml_rec rec;
580         struct file *file;
581         struct presto_cache *cache;
582         struct presto_file_set *fset;
583         struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
584         struct run_ctxt saved_ctxt;
585         int     error;
586
587         ENTRY;
588
589         error = presto_prep(dir->f_dentry, &cache, &fset);
590         if ( error  ) {
591                 CERROR("intermezzo: Reintegration on invalid file\n");
592                 return error;
593         }
594
595         if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
596                 CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
597                        dir->f_dentry->d_inode->i_ino);
598                     
599                 return -EINVAL;
600         }
601
602
603         PRESTO_ALLOC(buf, data->ioc_plen1);
604         if (!buf) { 
605                 EXIT;
606                 return -ENOMEM;
607         }
608         ptr = buf;
609         end = buf + data->ioc_plen1;
610
611         if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
612                 EXIT;
613                 PRESTO_FREE(buf, data->ioc_plen1);
614                 return -EFAULT;
615         }
616
617         error = kml_unpack(&rec, &ptr, end);
618         if (error) { 
619                 EXIT;
620                 PRESTO_FREE(buf, data->ioc_plen1);
621                 return -EFAULT;
622         }
623
624         kmlreint_pre_secure(&rec, dir, &saved_ctxt);
625
626         file = filp_open(rec.path, O_RDONLY, 0);
627         if (!file || IS_ERR(file)) { 
628                 error = PTR_ERR(file);
629                 goto out;
630         }
631         data->ioc_ino = file->f_dentry->d_inode->i_ino;
632         data->ioc_generation = file->f_dentry->d_inode->i_generation; 
633         filp_close(file, 0); 
634
635         CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path,
636                (unsigned long long) data->ioc_ino,
637                (unsigned long long) data->ioc_generation);
638
639  out:
640         if (buf) 
641                 PRESTO_FREE(buf, data->ioc_plen1);
642         pop_ctxt(&saved_ctxt); 
643         EXIT;
644         return error;
645 }
646
647