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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  2.  * vim:expandtab:shiftwidth=8:tabstop=8:
  3.  *
  4.  *  Author: Peter J. Braam <braam@clusterfs.com>
  5.  *  Copyright (C) 1998 Stelias Computing Inc
  6.  *  Copyright (C) 1999 Red Hat Inc.
  7.  *
  8.  *   This file is part of InterMezzo, http://www.inter-mezzo.org.
  9.  *
  10.  *   InterMezzo is free software; you can redistribute it and/or
  11.  *   modify it under the terms of version 2 of the GNU General Public
  12.  *   License as published by the Free Software Foundation.
  13.  *
  14.  *   InterMezzo is distributed in the hope that it will be useful,
  15.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *   GNU General Public License for more details.
  18.  *
  19.  *   You should have received a copy of the GNU General Public License
  20.  *   along with InterMezzo; if not, write to the Free Software
  21.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  *
  23.  * This file implements basic routines supporting the semantics
  24.  */
  25. #include <linux/types.h>
  26. #include <linux/kernel.h>
  27. #include <linux/sched.h>
  28. #include <linux/fs.h>
  29. #include <linux/stat.h>
  30. #include <linux/errno.h>
  31. #include <linux/vmalloc.h>
  32. #include <linux/slab.h>
  33. #include <linux/locks.h>
  34. #include <asm/segment.h>
  35. #include <asm/uaccess.h>
  36. #include <linux/string.h>
  37. #include <linux/smp_lock.h>
  38. #include <linux/intermezzo_fs.h>
  39. #include <linux/intermezzo_psdev.h>
  40. int presto_walk(const char *name, struct nameidata *nd)
  41. {
  42.         int err;
  43.         /* we do not follow symlinks to support symlink operations 
  44.            correctly. The vfs should always hand us resolved dentries
  45.            so we should not be required to use LOOKUP_FOLLOW. At the
  46.            reintegrating end, lento again should be working with the 
  47.            resolved pathname and not the symlink. SHP
  48.            XXX: This code implies that direct symlinks do not work. SHP
  49.         */
  50.         unsigned int flags = LOOKUP_POSITIVE;
  51.         ENTRY;
  52.         err = 0;
  53.         if (path_init(name, flags, nd)) 
  54.                 err = path_walk(name, nd);
  55.         return err;
  56. }
  57. /* find the presto minor device for this inode */
  58. int presto_i2m(struct inode *inode)
  59. {
  60.         struct presto_cache *cache;
  61.         ENTRY;
  62.         cache = presto_get_cache(inode);
  63.         CDEBUG(D_PSDEV, "n");
  64.         if ( !cache ) {
  65.                 CERROR("PRESTO: BAD: cannot find cache for dev %d, ino %ldn",
  66.                        inode->i_dev, inode->i_ino);
  67.                 EXIT;
  68.                 return -1;
  69.         }
  70.         EXIT;
  71.         return cache->cache_psdev->uc_minor;
  72. }
  73. inline int presto_f2m(struct presto_file_set *fset)
  74. {
  75.         return fset->fset_cache->cache_psdev->uc_minor;
  76. }
  77. inline int presto_c2m(struct presto_cache *cache)
  78. {
  79.         return cache->cache_psdev->uc_minor;
  80. }
  81. /* XXX check this out */
  82. struct presto_file_set *presto_path2fileset(const char *name)
  83. {
  84.         struct nameidata nd;
  85.         struct presto_file_set *fileset;
  86.         int error;
  87.         ENTRY;
  88.         error = presto_walk(name, &nd);
  89.         if (!error) { 
  90. #if 0
  91.                 error = do_revalidate(nd.dentry);
  92. #endif
  93.                 if (!error) 
  94.                         fileset = presto_fset(nd.dentry); 
  95.                 path_release(&nd); 
  96.                 EXIT;
  97.         } else 
  98.                 fileset = ERR_PTR(error);
  99.         EXIT;
  100.         return fileset;
  101. }
  102. /* check a flag on this dentry or fset root.  Semantics:
  103.    - most flags: test if it is set
  104.    - PRESTO_ATTR, PRESTO_DATA return 1 if PRESTO_FSETINSYNC is set
  105. */
  106. int presto_chk(struct dentry *dentry, int flag)
  107. {
  108.         int minor;
  109.         struct presto_file_set *fset = presto_fset(dentry);
  110.         ENTRY;
  111.         minor = presto_i2m(dentry->d_inode);
  112.         if ( izo_channels[minor].uc_no_filter ) {
  113.                 EXIT;
  114.                 return ~0;
  115.         }
  116.         /* if the fileset is in sync DATA and ATTR are OK */
  117.         if ( fset &&
  118.              (flag == PRESTO_ATTR || flag == PRESTO_DATA) &&
  119.              (fset->fset_flags & FSET_INSYNC) ) {
  120.                 CDEBUG(D_INODE, "fset in sync (ino %ld)!n",
  121.                        fset->fset_dentry->d_inode->i_ino);
  122.                 EXIT;
  123.                 return 1;
  124.         }
  125.         EXIT;
  126.         return (presto_d2d(dentry)->dd_flags & flag);
  127. }
  128. /* set a bit in the dentry flags */
  129. void presto_set(struct dentry *dentry, int flag)
  130. {
  131.         ENTRY;
  132.         if ( dentry->d_inode ) {
  133.                 CDEBUG(D_INODE, "SET ino %ld, flag %xn",
  134.                        dentry->d_inode->i_ino, flag);
  135.         }
  136.         if ( presto_d2d(dentry) == NULL) {
  137.                 CERROR("dentry without d_fsdata in presto_set: %p: %*s", dentry,
  138.                                 dentry->d_name.len, dentry->d_name.name);
  139.                 BUG();
  140.         }
  141.         presto_d2d(dentry)->dd_flags |= flag;
  142.         EXIT;
  143. }
  144. /* given a path: complete the closes on the fset */
  145. int lento_complete_closes(char *path)
  146. {
  147.         struct nameidata nd;
  148.         struct dentry *dentry;
  149.         int error;
  150.         struct presto_file_set *fset;
  151.         ENTRY;
  152.         error = presto_walk(path, &nd);
  153.         if (error) {
  154.                 EXIT;
  155.                 return error;
  156.         }
  157.         dentry = nd.dentry;
  158.         error = -ENXIO;
  159.         if ( !presto_ispresto(dentry->d_inode) ) {
  160.                 EXIT;
  161.                 goto out_complete;
  162.         }
  163.         
  164.         fset = presto_fset(dentry);
  165.         error = -EINVAL;
  166.         if ( !fset ) {
  167.                 CERROR("No fileset!n");
  168.                 EXIT;
  169.                 goto out_complete;
  170.         }
  171.         
  172.         /* transactions and locking are internal to this function */ 
  173.         error = presto_complete_lml(fset);
  174.         
  175.         EXIT;
  176.  out_complete:
  177.         path_release(&nd); 
  178.         return error;
  179. }       
  180. #if 0
  181. /* given a path: write a close record and cancel an LML record, finally
  182.    call truncate LML.  Lento is doing this so it goes in with uid/gid's 
  183.    root. 
  184. */ 
  185. int lento_cancel_lml(char *path, 
  186.                      __u64 lml_offset, 
  187.                      __u64 remote_ino, 
  188.                      __u32 remote_generation,
  189.                      __u32 remote_version, 
  190.                      struct lento_vfs_context *info)
  191. {
  192.         struct nameidata nd;
  193.         struct rec_info rec;
  194.         struct dentry *dentry;
  195.         int error;
  196.         struct presto_file_set *fset;
  197.         void *handle; 
  198.         struct presto_version new_ver;
  199.         ENTRY;
  200.         error = presto_walk(path, &nd);
  201.         if (error) {
  202.                 EXIT;
  203.                 return error;
  204.         }
  205.         dentry = nd.dentry;
  206.         error = -ENXIO;
  207.         if ( !presto_ispresto(dentry->d_inode) ) {
  208.                 EXIT;
  209.                 goto out_cancel_lml;
  210.         }
  211.         
  212.         fset = presto_fset(dentry);
  213.         error=-EINVAL;
  214.         if (fset==NULL) {
  215.                 CERROR("No fileset!n");
  216.                 EXIT;
  217.                 goto out_cancel_lml;
  218.         }
  219.         
  220.         /* this only requires a transaction below which is automatic */
  221.         handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_RELEASE); 
  222.         if ( IS_ERR(handle) ) {
  223.                 error = -ENOMEM; 
  224.                 EXIT; 
  225.                 goto out_cancel_lml; 
  226.         } 
  227.         
  228.         if (info->flags & LENTO_FL_CANCEL_LML) {
  229.                 error = presto_clear_lml_close(fset, lml_offset);
  230.                 if ( error ) {
  231.                         presto_trans_commit(fset, handle);
  232.                         EXIT; 
  233.                         goto out_cancel_lml;
  234.                 }
  235.         }
  236.         if (info->flags & LENTO_FL_WRITE_KML) {
  237.                 struct file file;
  238.                 file.private_data = NULL;
  239.                 file.f_dentry = dentry; 
  240.                 presto_getversion(&new_ver, dentry->d_inode);
  241.                 error = presto_journal_close(&rec, fset, &file, dentry, 
  242.                                              &new_ver);
  243.                 if ( error ) {
  244.                         EXIT; 
  245.                         presto_trans_commit(fset, handle);
  246.                         goto out_cancel_lml;
  247.                 }
  248.         }
  249.         if (info->flags & LENTO_FL_WRITE_EXPECT) {
  250.                 error = presto_write_last_rcvd(&rec, fset, info); 
  251.                 if ( error < 0 ) {
  252.                         EXIT; 
  253.                         presto_trans_commit(fset, handle);
  254.                         goto out_cancel_lml;
  255.                 }
  256.         }
  257.         presto_trans_commit(fset, handle);
  258.         if (info->flags & LENTO_FL_CANCEL_LML) {
  259.             presto_truncate_lml(fset); 
  260.         }
  261.                 
  262.  out_cancel_lml:
  263.         EXIT;
  264.         path_release(&nd); 
  265.         return error;
  266. }       
  267. #endif 
  268. /* given a dentry, operate on the flags in its dentry.  Used by downcalls */
  269. int izo_mark_dentry(struct dentry *dentry, int and_flag, int or_flag, 
  270.                        int *res)
  271. {
  272.         int error = 0;
  273.         if (presto_d2d(dentry) == NULL) {
  274.                 CERROR("InterMezzo: no ddata for inode %ld in %sn",
  275.                        dentry->d_inode->i_ino, __FUNCTION__);
  276.                 return -EINVAL;
  277.         }
  278.         CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %xn",
  279.                dentry->d_inode->i_ino, and_flag, or_flag,
  280.                presto_d2d(dentry)->dd_flags);
  281.         presto_d2d(dentry)->dd_flags &= and_flag;
  282.         presto_d2d(dentry)->dd_flags |= or_flag;
  283.         if (res) 
  284.                 *res = presto_d2d(dentry)->dd_flags;
  285.         return error;
  286. }
  287. /* given a path, operate on the flags in its cache.  Used by mark_ioctl */
  288. int izo_mark_cache(struct dentry *dentry, int and_flag, int or_flag, 
  289.                    int *res)
  290. {
  291.         struct presto_cache *cache;
  292.         if (presto_d2d(dentry) == NULL) {
  293.                 CERROR("InterMezzo: no ddata for inode %ld in %sn",
  294.                        dentry->d_inode->i_ino, __FUNCTION__);
  295.                 return -EINVAL;
  296.         }
  297.         CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %xn",
  298.                dentry->d_inode->i_ino, and_flag, or_flag,
  299.                presto_d2d(dentry)->dd_flags);
  300.         cache = presto_get_cache(dentry->d_inode);
  301.         if ( !cache ) {
  302.                 CERROR("PRESTO: BAD: cannot find cache in izo_mark_cachen");
  303.                 return -EBADF;
  304.         }
  305.         ((int)cache->cache_flags) &= and_flag;
  306.         ((int)cache->cache_flags) |= or_flag;
  307.         if (res)
  308.                 *res = (int)cache->cache_flags;
  309.         return 0;
  310. }
  311. int presto_set_max_kml_size(const char *path, unsigned long max_size)
  312. {
  313.         struct presto_file_set *fset;
  314.         ENTRY;
  315.         fset = presto_path2fileset(path);
  316.         if (IS_ERR(fset)) {
  317.                 EXIT;
  318.                 return PTR_ERR(fset);
  319.         }
  320.         fset->kml_truncate_size = max_size;
  321.         CDEBUG(D_CACHE, "KML truncate size set to %lu bytes for fset %s.n",
  322.                max_size, path);
  323.         EXIT;
  324.         return 0;
  325. }
  326. int izo_mark_fset(struct dentry *dentry, int and_flag, int or_flag, 
  327.                   int * res)
  328. {
  329.         struct presto_file_set *fset;
  330.         
  331.         fset = presto_fset(dentry);
  332.         if ( !fset ) {
  333.                 CERROR("PRESTO: BAD: cannot find cache in izo_mark_cachen");
  334.                 make_bad_inode(dentry->d_inode);
  335.                 return -EBADF;
  336.         }
  337.         ((int)fset->fset_flags) &= and_flag;
  338.         ((int)fset->fset_flags) |= or_flag;
  339.         if (res)
  340.                 *res = (int)fset->fset_flags;
  341.         return 0;
  342. }
  343. /* talk to Lento about the permit */
  344. static int presto_permit_upcall(struct dentry *dentry)
  345. {
  346.         int rc;
  347.         char *path, *buffer;
  348.         int pathlen;
  349.         int minor;
  350.         int fsetnamelen;
  351.         struct presto_file_set *fset = NULL;
  352.         ENTRY;
  353.         if ( (minor = presto_i2m(dentry->d_inode)) < 0) {
  354.                 EXIT;
  355.                 return -EINVAL;
  356.         }
  357.         fset = presto_fset(dentry);
  358.         if (!fset) {
  359.                 EXIT;
  360.                 return -ENOTCONN;
  361.         }
  362.         
  363.         if ( !presto_lento_up(minor) ) {
  364.                 if ( fset->fset_flags & FSET_STEAL_PERMIT ) {
  365.                         EXIT;
  366.                         return 0;
  367.                 } else {
  368.                         EXIT;
  369.                         return -ENOTCONN;
  370.                 }
  371.         }
  372.         PRESTO_ALLOC(buffer, PAGE_SIZE);
  373.         if ( !buffer ) {
  374.                 CERROR("PRESTO: out of memory!n");
  375.                 EXIT;
  376.                 return -ENOMEM;
  377.         }
  378.         path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE);
  379.         pathlen = MYPATHLEN(buffer, path);
  380.         fsetnamelen = strlen(fset->fset_name); 
  381.         rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name);
  382.         PRESTO_FREE(buffer, PAGE_SIZE);
  383.         EXIT;
  384.         return rc;
  385. }
  386. /* get a write permit for the fileset of this inode
  387.  *  - if this returns a negative value there was an error
  388.  *  - if 0 is returned the permit was already in the kernel -- or --
  389.  *    Lento gave us the permit without reintegration
  390.  *  - lento returns the number of records it reintegrated 
  391.  *
  392.  * Note that if this fileset has branches, a permit will -never- to a normal
  393.  * process for writing in the data area (ie, outside of .intermezzo)
  394.  */
  395. int presto_get_permit(struct inode * inode)
  396. {
  397.         struct dentry *de;
  398.         struct presto_file_set *fset;
  399.         int minor = presto_i2m(inode);
  400.         int rc = 0;
  401.         ENTRY;
  402.         if (minor < 0) {
  403.                 EXIT;
  404.                 return -1;
  405.         }
  406.         if ( ISLENTO(minor) ) {
  407.                 EXIT;
  408.                 return 0;
  409.         }
  410.         if (list_empty(&inode->i_dentry)) {
  411.                 CERROR("No alias for inode %dn", (int) inode->i_ino);
  412.                 EXIT;
  413.                 return -EINVAL;
  414.         }
  415.         de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
  416.         if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
  417.                 EXIT;
  418.                 return 0;
  419.         }
  420.         fset = presto_fset(de);
  421.         if ( !fset ) {
  422.                 CERROR("Presto: no fileset in presto_get_permit!n");
  423.                 EXIT;
  424.                 return -EINVAL;
  425.         }
  426.         if (fset->fset_flags & FSET_HAS_BRANCHES) {
  427.                 EXIT;
  428.                 return -EROFS;
  429.         }
  430.         spin_lock(&fset->fset_permit_lock);
  431.         if (fset->fset_flags & FSET_HASPERMIT) {
  432.                 fset->fset_permit_count++;
  433.                 CDEBUG(D_INODE, "permit count now %d, inode %lxn", 
  434.                        fset->fset_permit_count, inode->i_ino);
  435.                 spin_unlock(&fset->fset_permit_lock);
  436.                 EXIT;
  437.                 return 0;
  438.         }
  439.         /* Allow reintegration to proceed without locks -SHP */
  440.         fset->fset_permit_upcall_count++;
  441.         if (fset->fset_permit_upcall_count == 1) {
  442.                 spin_unlock(&fset->fset_permit_lock);
  443.                 rc = presto_permit_upcall(fset->fset_dentry);
  444.                 spin_lock(&fset->fset_permit_lock);
  445.                 fset->fset_permit_upcall_count--;
  446.                 if (rc == 0) {
  447.                         izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
  448.                                       NULL);
  449.                         fset->fset_permit_count++;
  450.                 } else if (rc == ENOTCONN) {
  451.                         CERROR("InterMezzo: disconnected operation. stealing permit.n");
  452.                         izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
  453.                                       NULL);
  454.                         fset->fset_permit_count++;
  455.                         /* set a disconnected flag here to stop upcalls */
  456.                         rc = 0;
  457.                 } else {
  458.                         CERROR("InterMezzo: presto_permit_upcall failed: %dn", rc);
  459.                         rc = -EROFS;
  460.                         /* go to sleep here and try again? */
  461.                 }
  462.                 wake_up_interruptible(&fset->fset_permit_queue);
  463.         } else {
  464.                 /* Someone is already doing an upcall; go to sleep. */
  465.                 DECLARE_WAITQUEUE(wait, current);
  466.                 spin_unlock(&fset->fset_permit_lock);
  467.                 add_wait_queue(&fset->fset_permit_queue, &wait);
  468.                 while (1) {
  469.                         set_current_state(TASK_INTERRUPTIBLE);
  470.                         spin_lock(&fset->fset_permit_lock);
  471.                         if (fset->fset_permit_upcall_count == 0)
  472.                                 break;
  473.                         spin_unlock(&fset->fset_permit_lock);
  474.                         if (signal_pending(current)) {
  475.                                 remove_wait_queue(&fset->fset_permit_queue,
  476.                                                   &wait);
  477.                                 return -ERESTARTSYS;
  478.                         }
  479.                         schedule();
  480.                 }
  481.                 remove_wait_queue(&fset->fset_permit_queue, &wait);
  482.                 /* We've been woken up: do we have the permit? */
  483.                 if (fset->fset_flags & FSET_HASPERMIT)
  484.                         /* FIXME: Is this the right thing? */
  485.                         rc = -EAGAIN;
  486.         }
  487.         CDEBUG(D_INODE, "permit count now %d, ino %ld (likely 1), "
  488.                "rc %dn", fset->fset_permit_count, inode->i_ino, rc);
  489.         spin_unlock(&fset->fset_permit_lock);
  490.         EXIT;
  491.         return rc;
  492. }
  493. int presto_put_permit(struct inode * inode)
  494. {
  495.         struct dentry *de;
  496.         struct presto_file_set *fset;
  497.         int minor = presto_i2m(inode);
  498.         ENTRY;
  499.         if (minor < 0) {
  500.                 EXIT;
  501.                 return -1;
  502.         }
  503.         if ( ISLENTO(minor) ) {
  504.                 EXIT;
  505.                 return 0;
  506.         }
  507.         if (list_empty(&inode->i_dentry)) {
  508.                 CERROR("No alias for inode %dn", (int) inode->i_ino);
  509.                 EXIT;
  510.                 return -1;
  511.         }
  512.         de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
  513.         fset = presto_fset(de);
  514.         if ( !fset ) {
  515.                 CERROR("InterMezzo: no fileset in %s!n", __FUNCTION__);
  516.                 EXIT;
  517.                 return -1;
  518.         }
  519.         if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
  520.                 EXIT;
  521.                 return 0;
  522.         }
  523.         spin_lock(&fset->fset_permit_lock);
  524.         if (fset->fset_flags & FSET_HASPERMIT) {
  525.                 if (fset->fset_permit_count > 0)
  526.                         fset->fset_permit_count--;
  527.                 else
  528.                         CERROR("Put permit while permit count is 0, "
  529.                                "inode %ld!n", inode->i_ino); 
  530.         } else {
  531.                 fset->fset_permit_count = 0;
  532.                 CERROR("InterMezzo: put permit while no permit, inode %ld, "
  533.                        "flags %x!n", inode->i_ino, fset->fset_flags);
  534.         }
  535.         CDEBUG(D_INODE, "permit count now %d, inode %ldn",
  536.                fset->fset_permit_count, inode->i_ino);
  537.         if (fset->fset_flags & FSET_PERMIT_WAITING &&
  538.             fset->fset_permit_count == 0) {
  539.                 CDEBUG(D_INODE, "permit count now 0, ino %ld, wake sleepersn",
  540.                        inode->i_ino);
  541.                 wake_up_interruptible(&fset->fset_permit_queue);
  542.         }
  543.         spin_unlock(&fset->fset_permit_lock);
  544.         EXIT;
  545.         return 0;
  546. }
  547. void presto_getversion(struct presto_version * presto_version,
  548.                        struct inode * inode)
  549. {
  550.         presto_version->pv_mtime = (__u64)inode->i_mtime;
  551.         presto_version->pv_ctime = (__u64)inode->i_ctime;
  552.         presto_version->pv_size  = (__u64)inode->i_size;
  553. }
  554. /* If uuid is non-null, it is the uuid of the peer that's making the revocation
  555.  * request.  If it is null, this request was made locally, without external
  556.  * pressure to give up the permit.  This most often occurs when a client
  557.  * starts up.
  558.  *
  559.  * FIXME: this function needs to be refactored slightly once we start handling
  560.  * multiple clients.
  561.  */
  562. int izo_revoke_permit(struct dentry *dentry, __u8 uuid[16])
  563. {
  564.         struct presto_file_set *fset; 
  565.         DECLARE_WAITQUEUE(wait, current);
  566.         int minor, rc;
  567.         ENTRY;
  568.         minor = presto_i2m(dentry->d_inode);
  569.         if (minor < 0) {
  570.                 EXIT;
  571.                 return -ENODEV;
  572.         }
  573.         fset = presto_fset(dentry);
  574.         if (fset == NULL) {
  575.                 EXIT;
  576.                 return -ENODEV;
  577.         }
  578.         spin_lock(&fset->fset_permit_lock);
  579.         if (fset->fset_flags & FSET_PERMIT_WAITING) {
  580.                 CERROR("InterMezzo: Two processes are waiting on the same permit--this not yet supported!  Aborting this particular permit request...n");
  581.                 EXIT;
  582.                 spin_unlock(&fset->fset_permit_lock);
  583.                 return -EINVAL;
  584.         }
  585.         if (fset->fset_permit_count == 0)
  586.                 goto got_permit;
  587.         /* Something is still using this permit.  Mark that we're waiting for it
  588.          * and go to sleep. */
  589.         rc = izo_mark_fset(dentry, ~0, FSET_PERMIT_WAITING, NULL);
  590.         spin_unlock(&fset->fset_permit_lock);
  591.         if (rc < 0) {
  592.                 EXIT;
  593.                 return rc;
  594.         }
  595.         add_wait_queue(&fset->fset_permit_queue, &wait);
  596.         while (1) {
  597.                 set_current_state(TASK_INTERRUPTIBLE);
  598.                 spin_lock(&fset->fset_permit_lock);
  599.                 if (fset->fset_permit_count == 0)
  600.                         break;
  601.                 spin_unlock(&fset->fset_permit_lock);
  602.                 if (signal_pending(current)) {
  603.                         /* FIXME: there must be a better thing to return... */
  604.                         remove_wait_queue(&fset->fset_permit_queue, &wait);
  605.                         EXIT;
  606.                         return -ERESTARTSYS;
  607.                 }
  608.                 /* FIXME: maybe there should be a timeout here. */
  609.                 schedule();
  610.         }
  611.         remove_wait_queue(&fset->fset_permit_queue, &wait);
  612.  got_permit:
  613.         /* By this point fset->fset_permit_count is zero and we're holding the
  614.          * lock. */
  615.         CDEBUG(D_CACHE, "InterMezzo: releasing permit inode %ldn",
  616.                dentry->d_inode->i_ino);
  617.         if (uuid != NULL) {
  618.                 rc = izo_upc_revoke_permit(minor, fset->fset_name, uuid);
  619.                 if (rc < 0) {
  620.                         spin_unlock(&fset->fset_permit_lock);
  621.                         EXIT;
  622.                         return rc;
  623.                 }
  624.         }
  625.         izo_mark_fset(fset->fset_dentry, ~FSET_PERMIT_WAITING, 0, NULL);
  626.         izo_mark_fset(fset->fset_dentry, ~FSET_HASPERMIT, 0, NULL);
  627.         spin_unlock(&fset->fset_permit_lock);
  628.         EXIT;
  629.         return 0;
  630. }
  631. inline int presto_is_read_only(struct presto_file_set * fset)
  632. {
  633.         int minor, mask;
  634.         struct presto_cache *cache = fset->fset_cache;
  635.         minor= cache->cache_psdev->uc_minor;
  636.         mask= (ISLENTO(minor)? FSET_LENTO_RO : FSET_CLIENT_RO);
  637.         if ( fset->fset_flags & mask )
  638.                 return 1;
  639.         mask= (ISLENTO(minor)? CACHE_LENTO_RO : CACHE_CLIENT_RO);
  640.         return  ((cache->cache_flags & mask)? 1 : 0);
  641. }