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 * Managing filesets 22 * 23 */ 24 25#define __NO_VERSION__ 26#include <stdarg.h> 27 28#include <asm/bitops.h> 29#include <asm/uaccess.h> 30#include <asm/system.h> 31 32#include <linux/errno.h> 33#include <linux/fs.h> 34#include <linux/ext2_fs.h> 35#include <linux/slab.h> 36#include <linux/vmalloc.h> 37#include <linux/sched.h> 38#include <linux/stat.h> 39#include <linux/string.h> 40#include <linux/locks.h> 41#include <linux/blkdev.h> 42#include <linux/init.h> 43#include <linux/module.h> 44 45#include <linux/intermezzo_fs.h> 46#include <linux/intermezzo_psdev.h> 47 48static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry) 49{ 50 if (presto_d2d(dentry) == NULL) { 51 EXIT; 52 return NULL; 53 } 54 return presto_d2d(dentry)->dd_fset; 55} 56 57/* find the fileset dentry for this dentry */ 58struct presto_file_set *presto_fset(struct dentry *de) 59{ 60 struct dentry *fsde; 61 ENTRY; 62 if ( !de->d_inode ) { 63 CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n", 64 de->d_name.len, de->d_name.name); 65 } 66 for (fsde = de;; fsde = fsde->d_parent) { 67 if ( presto_dentry2fset(fsde) ) { 68 EXIT; 69 return presto_dentry2fset(fsde); 70 } 71 if (fsde->d_parent == fsde) 72 break; 73 } 74 EXIT; 75 return NULL; 76} 77 78int presto_get_lastrecno(char *path, off_t *recno) 79{ 80 struct nameidata nd; 81 struct presto_file_set *fset; 82 struct dentry *dentry; 83 int error; 84 ENTRY; 85 86 error = presto_walk(path, &nd); 87 if (error) { 88 EXIT; 89 return error; 90 } 91 92 dentry = nd.dentry; 93 94 error = -ENXIO; 95 if ( !presto_ispresto(dentry->d_inode) ) { 96 EXIT; 97 goto kml_out; 98 } 99 100 error = -EINVAL; 101 if ( ! presto_dentry2fset(dentry)) { 102 EXIT; 103 goto kml_out; 104 } 105 106 fset = presto_dentry2fset(dentry); 107 if (!fset) { 108 EXIT; 109 goto kml_out; 110 } 111 error = 0; 112 *recno = fset->fset_kml.fd_recno; 113 114 kml_out: 115 path_release(&nd); 116 return error; 117} 118 119static char * _izo_make_path(char *fsetname, char *name) 120{ 121 char *path = NULL; 122 int len; 123 124 len = strlen("/.intermezzo/") + strlen(fsetname) 125 + 1 + strlen(name) + 1; 126 127 PRESTO_ALLOC(path, len); 128 if (path == NULL) 129 return NULL; 130 131 sprintf(path, "/.intermezzo/%s/%s", fsetname, name); 132 133 return path; 134} 135 136char * izo_make_path(struct presto_file_set *fset, char *name) 137{ 138 return _izo_make_path(fset->fset_name, name); 139} 140 141static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode) 142{ 143 char *path; 144 struct file *f; 145 int error; 146 ENTRY; 147 148 path = _izo_make_path(fsetname, name); 149 if (path == NULL) { 150 EXIT; 151 return ERR_PTR(-ENOMEM); 152 } 153 154 CDEBUG(D_INODE, "opening file %s\n", path); 155 f = filp_open(path, flags, mode); 156 error = PTR_ERR(f); 157 if (IS_ERR(f)) { 158 CDEBUG(D_INODE, "Error %d\n", error); 159 } 160 161 PRESTO_FREE(path, strlen(path)); 162 163 EXIT; 164 return f; 165 166} 167 168struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode) 169{ 170 return _izo_fset_open(fset->fset_name, name, flags, mode); 171} 172 173 174 175/* 176 * note: this routine "pins" a dentry for a fileset root 177 */ 178int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname, 179 unsigned int flags) 180{ 181 struct presto_file_set *fset = NULL; 182 struct presto_cache *cache; 183 int error; 184 struct file *fset_root; 185 struct dentry *dentry; 186 187 ENTRY; 188 189 fset_root = _izo_fset_open(fsetname, "ROOT", O_RDONLY, 000); 190 if (IS_ERR(fset_root)) { 191 CERROR("Can't open %s/ROOT\n", fsetname); 192 EXIT; 193 error = PTR_ERR(fset_root); 194 goto out; 195 } 196 dentry = dget(fset_root->f_dentry); 197 filp_close(fset_root, NULL); 198 199 dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op; 200 dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop; 201 dentry->d_op = ioctl_dentry->d_op; 202 fset = presto_dentry2fset(dentry); 203 if (fset && (fset->fset_dentry == dentry) ) { 204 CERROR("Fsetroot already set (inode %ld)\n", 205 dentry->d_inode->i_ino); 206 } 207 208 cache = presto_get_cache(dentry->d_inode); 209 if (!cache) { 210 CERROR("No cache found for inode %ld\n", 211 dentry->d_inode->i_ino); 212 EXIT; 213 error = -ENODEV; 214 goto out_free; 215 } 216 217 PRESTO_ALLOC(fset, sizeof(*fset)); 218 if ( !fset ) { 219 CERROR("No memory allocating fset for %s\n", fsetname); 220 EXIT; 221 error = -ENOMEM; 222 goto out_free; 223 } 224 CDEBUG(D_INODE, "fset at %p\n", fset); 225 226 CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n", 227 dentry->d_inode->i_ino, fsetname); 228 229 fset->fset_mnt = mntget(current->fs->pwdmnt); 230 fset->fset_cache = cache; 231 fset->fset_dentry = dentry; 232 fset->fset_name = strdup(fsetname); 233 fset->fset_chunkbits = CHUNK_BITS; 234 fset->fset_flags = flags; 235 fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 236 fset->fset_permit_lock = SPIN_LOCK_UNLOCKED; 237 PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024); 238 if (fset->fset_reint_buf == NULL) { 239 EXIT; 240 error = -ENOMEM; 241 goto out_free; 242 } 243 init_waitqueue_head(&fset->fset_permit_queue); 244 245 if (presto_d2d(dentry) == NULL) { 246 dentry->d_fsdata = izo_alloc_ddata(); 247 } 248 if (presto_d2d(dentry) == NULL) { 249 CERROR("InterMezzo: %s: no memory\n", __FUNCTION__); 250 EXIT; 251 error = -ENOMEM; 252 goto out_free; 253 } 254 presto_d2d(dentry)->dd_fset = fset; 255 list_add(&fset->fset_list, &cache->cache_fset_list); 256 257 error = izo_init_kml_file(fset, &fset->fset_kml); 258 if ( error ) { 259 EXIT; 260 CDEBUG(D_JOURNAL, "Error init_kml %d\n", error); 261 goto out_list_del; 262 } 263 264 error = izo_init_lml_file(fset, &fset->fset_lml); 265 if ( error ) { 266 int rc; 267 EXIT; 268 rc = izo_log_close(&fset->fset_kml); 269 CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc); 270 goto out_list_del; 271 } 272 273 /* init_last_rcvd_file could trigger a presto_file_write(), which 274 * requires that the lml structure be initialized. -phil */ 275 error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd); 276 if ( error ) { 277 int rc; 278 EXIT; 279 rc = izo_log_close(&fset->fset_kml); 280 rc = izo_log_close(&fset->fset_lml); 281 CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc); 282 goto out_list_del; 283 } 284 285 CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p," 286 "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n", 287 fset, dentry, fset->fset_dentry, fset->fset_name, cache, 288 presto_d2d(dentry)->dd_fset); 289 290 EXIT; 291 return 0; 292 293 out_list_del: 294 list_del(&fset->fset_list); 295 presto_d2d(dentry)->dd_fset = NULL; 296 out_free: 297 if (fset) { 298 mntput(fset->fset_mnt); 299 if (fset->fset_reint_buf != NULL) 300 PRESTO_FREE(fset->fset_reint_buf, 64 * 1024); 301 PRESTO_FREE(fset, sizeof(*fset)); 302 } 303 dput(dentry); 304 out: 305 return error; 306} 307 308static int izo_cleanup_fset(struct presto_file_set *fset) 309{ 310 int error; 311 struct presto_cache *cache; 312 313 ENTRY; 314 315 CERROR("Cleaning up fset %s\n", fset->fset_name); 316 317 error = izo_log_close(&fset->fset_kml); 318 if (error) 319 CERROR("InterMezzo: Closing kml for fset %s: %d\n", 320 fset->fset_name, error); 321 error = izo_log_close(&fset->fset_lml); 322 if (error) 323 CERROR("InterMezzo: Closing lml for fset %s: %d\n", 324 fset->fset_name, error); 325 error = izo_log_close(&fset->fset_rcvd); 326 if (error) 327 CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n", 328 fset->fset_name, error); 329 330 cache = fset->fset_cache; 331 332 list_del(&fset->fset_list); 333 334 presto_d2d(fset->fset_dentry)->dd_fset = NULL; 335 dput(fset->fset_dentry); 336 mntput(fset->fset_mnt); 337 338 PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1); 339 PRESTO_FREE(fset->fset_reint_buf, 64 * 1024); 340 PRESTO_FREE(fset, sizeof(*fset)); 341 EXIT; 342 return error; 343} 344 345int izo_clear_fsetroot(struct dentry *dentry) 346{ 347 struct presto_file_set *fset; 348 349 ENTRY; 350 351 fset = presto_dentry2fset(dentry); 352 if (!fset) { 353 EXIT; 354 return -EINVAL; 355 } 356 357 izo_cleanup_fset(fset); 358 EXIT; 359 return 0; 360} 361 362int izo_clear_all_fsetroots(struct presto_cache *cache) 363{ 364 struct presto_file_set *fset; 365 struct list_head *tmp,*tmpnext; 366 int error; 367 368 error = 0; 369 tmp = &cache->cache_fset_list; 370 tmpnext = tmp->next; 371 while ( tmpnext != &cache->cache_fset_list) { 372 tmp = tmpnext; 373 tmpnext = tmp->next; 374 fset = list_entry(tmp, struct presto_file_set, fset_list); 375 376 error = izo_cleanup_fset(fset); 377 if (error) 378 break; 379 } 380 return error; 381} 382 383static struct vfsmount *izo_alloc_vfsmnt(void) 384{ 385 struct vfsmount *mnt; 386 PRESTO_ALLOC(mnt, sizeof(*mnt)); 387 if (mnt) { 388 memset(mnt, 0, sizeof(struct vfsmount)); 389 atomic_set(&mnt->mnt_count,1); 390 INIT_LIST_HEAD(&mnt->mnt_hash); 391 INIT_LIST_HEAD(&mnt->mnt_child); 392 INIT_LIST_HEAD(&mnt->mnt_mounts); 393 INIT_LIST_HEAD(&mnt->mnt_list); 394 } 395 return mnt; 396} 397 398 399static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt, 400 struct run_ctxt *save) 401{ 402 struct run_ctxt new; 403 404 mnt->mnt_root = root; 405 mnt->mnt_sb = root->d_inode->i_sb; 406 unlock_super(mnt->mnt_sb); 407 408 new.rootmnt = mnt; 409 new.root = root; 410 new.pwdmnt = mnt; 411 new.pwd = root; 412 new.fsuid = 0; 413 new.fsgid = 0; 414 new.fs = get_fs(); 415 new.ngroups = 0; 416 417 push_ctxt(save, &new); 418} 419 420static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) 421{ 422 lock_super(mnt->mnt_sb); 423 pop_ctxt(save); 424} 425 426static int izo_simple_mkdir(struct dentry *dir, char *name, int mode) 427{ 428 struct dentry *dchild; 429 int err; 430 ENTRY; 431 432 dchild = lookup_one_len(name, dir, strlen(name)); 433 if (IS_ERR(dchild)) { 434 EXIT; 435 return PTR_ERR(dchild); 436 } 437 438 if (dchild->d_inode) { 439 dput(dchild); 440 EXIT; 441 return -EEXIST; 442 } 443 444 err = vfs_mkdir(dir->d_inode, dchild, mode); 445 dput(dchild); 446 447 EXIT; 448 return err; 449} 450 451static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt) 452{ 453 struct dentry *dchild; 454 int err; 455 ENTRY; 456 457 dchild = lookup_one_len(name, dir, strlen(name)); 458 if (IS_ERR(dchild)) { 459 EXIT; 460 return PTR_ERR(dchild); 461 } 462 463 if (dchild->d_inode) { 464 dput(dchild); 465 EXIT; 466 return -EEXIST; 467 } 468 469 err = vfs_symlink(dir->d_inode, dchild, tgt); 470 dput(dchild); 471 472 EXIT; 473 return err; 474} 475 476/* 477 * run set_fsetroot in chroot environment 478 */ 479int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname, 480 unsigned int flags) 481{ 482 int rc; 483 struct presto_cache *cache; 484 struct vfsmount *mnt; 485 struct run_ctxt save; 486 487 if (root != root->d_inode->i_sb->s_root) { 488 CERROR ("IOC_SET_FSET must be called on mount point\n"); 489 return -ENODEV; 490 } 491 492 cache = presto_get_cache(root->d_inode); 493 mnt = cache->cache_vfsmount; 494 if (!mnt) { 495 EXIT; 496 return -ENOMEM; 497 } 498 499 izo_setup_ctxt(root, mnt, &save); 500 rc = presto_set_fsetroot(root, fsetname, flags); 501 izo_cleanup_ctxt(mnt, &save); 502 return rc; 503} 504 505int izo_prepare_fileset(struct dentry *root, char *fsetname) 506{ 507 int err; 508 struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; 509 struct presto_cache *cache; 510 struct vfsmount *mnt; 511 struct run_ctxt save; 512 513 cache = presto_get_cache(root->d_inode); 514 mnt = cache->cache_vfsmount = izo_alloc_vfsmnt(); 515 if (!mnt) { 516 EXIT; 517 return -ENOMEM; 518 } 519 520 if (!fsetname) 521 fsetname = "rootfset"; 522 523 izo_setup_ctxt(root, mnt, &save); 524 525 err = izo_simple_mkdir(root, ".intermezzo", 0755); 526 CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); 527 528 err = izo_simple_mkdir(root, "..iopen..", 0755); 529 CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); 530 531 dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen..")); 532 if (IS_ERR(dotiopen)) { 533 EXIT; 534 goto out; 535 } 536 dotiopen->d_inode->i_op = &presto_dir_iops; 537 dput(dotiopen); 538 539 540 dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo")); 541 if (IS_ERR(dotizo)) { 542 EXIT; 543 goto out; 544 } 545 546 547 err = izo_simple_mkdir(dotizo, fsetname, 0755); 548 CDEBUG(D_CACHE, "mkdir err %d\n", err); 549 550 fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname)); 551 if (IS_ERR(fsetdir)) { 552 EXIT; 553 goto out; 554 } 555 556 err = izo_simple_symlink(fsetdir, "ROOT", "../.."); 557 558 err = presto_set_fsetroot(root, fsetname, 0); 559 CDEBUG(D_CACHE, "set_fsetroot err %d\n", err); 560 561 out: 562 if (dotizo && !IS_ERR(dotizo)) 563 dput(dotizo); 564 if (fsetdir && !IS_ERR(fsetdir)) 565 dput(fsetdir); 566 izo_cleanup_ctxt(mnt, &save); 567 return err; 568} 569 570int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data) 571{ 572 int rc = 0; 573 struct presto_cache *cache; 574 struct vfsmount *mnt; 575 struct run_ctxt save; 576 struct nameidata nd; 577 struct dentry *dentry; 578 struct presto_dentry_data *dd; 579 struct dentry *root; 580 char *buf = NULL; 581 582 ENTRY; 583 584 585 root = dir->f_dentry; 586 587 /* actually, needs to be called on ROOT of fset, not mount point 588 if (root != root->d_inode->i_sb->s_root) { 589 CERROR ("IOC_SET_FSET must be called on mount point\n"); 590 return -ENODEV; 591 } 592 */ 593 594 cache = presto_get_cache(root->d_inode); 595 mnt = cache->cache_vfsmount; 596 if (!mnt) { 597 EXIT; 598 return -ENOMEM; 599 } 600 601 izo_setup_ctxt(root, mnt, &save); 602 603 PRESTO_ALLOC(buf, data->ioc_plen1); 604 if (!buf) { 605 rc = -ENOMEM; 606 EXIT; 607 goto out; 608 } 609 if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 610 rc = -EFAULT; 611 EXIT; 612 goto out; 613 } 614 615 rc = presto_walk(buf, &nd); 616 if (rc) { 617 CERROR("Unable to open: %s\n", buf); 618 EXIT; 619 goto out; 620 } 621 dentry = nd.dentry; 622 if (!dentry) { 623 CERROR("no dentry!\n"); 624 rc = -EINVAL; 625 EXIT; 626 goto out_close; 627 } 628 dd = presto_d2d(dentry); 629 if (!dd) { 630 CERROR("no dentry_data!\n"); 631 rc = -EINVAL; 632 EXIT; 633 goto out_close; 634 } 635 636 CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd); 637 638 if (dd->remote_ino != 0) { 639 CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino, 640 dd->remote_generation); 641 rc = 0; 642 EXIT; 643 goto out_close; 644 } 645 646 647 CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 648 buf, data->ioc_ino, 649 data->ioc_generation); 650 dd->remote_ino = data->ioc_ino; 651 dd->remote_generation = data->ioc_generation; 652 653 EXIT; 654 out_close: 655 path_release(&nd); 656 out: 657 if (buf) 658 PRESTO_FREE(buf, data->ioc_plen1); 659 izo_cleanup_ctxt(mnt, &save); 660 return rc; 661} 662