fileset.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:18k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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