[PATCH] r/o bind mount prepwork: inc_nlink() helper
[safe/jmp/linux-2.6] / net / sunrpc / rpc_pipe.c
index 81e00a6..9a0b41a 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no>
  *
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -38,38 +37,42 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly;
 
 #define RPC_UPCALL_TIMEOUT (30*HZ)
 
-static void
-__rpc_purge_upcall(struct inode *inode, int err)
+static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
+               void (*destroy_msg)(struct rpc_pipe_msg *), int err)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
        struct rpc_pipe_msg *msg;
 
-       while (!list_empty(&rpci->pipe)) {
-               msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list);
-               list_del_init(&msg->list);
-               msg->errno = err;
-               rpci->ops->destroy_msg(msg);
-       }
-       while (!list_empty(&rpci->in_upcall)) {
-               msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list);
-               list_del_init(&msg->list);
+       if (list_empty(head))
+               return;
+       do {
+               msg = list_entry(head->next, struct rpc_pipe_msg, list);
+               list_del(&msg->list);
                msg->errno = err;
-               rpci->ops->destroy_msg(msg);
-       }
-       rpci->pipelen = 0;
+               destroy_msg(msg);
+       } while (!list_empty(head));
        wake_up(&rpci->waitq);
 }
 
 static void
 rpc_timeout_upcall_queue(void *data)
 {
+       LIST_HEAD(free_list);
        struct rpc_inode *rpci = (struct rpc_inode *)data;
        struct inode *inode = &rpci->vfs_inode;
+       void (*destroy_msg)(struct rpc_pipe_msg *);
 
-       down(&inode->i_sem);
-       if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
-               __rpc_purge_upcall(inode, -ETIMEDOUT);
-       up(&inode->i_sem);
+       spin_lock(&inode->i_lock);
+       if (rpci->ops == NULL) {
+               spin_unlock(&inode->i_lock);
+               return;
+       }
+       destroy_msg = rpci->ops->destroy_msg;
+       if (rpci->nreaders == 0) {
+               list_splice_init(&rpci->pipe, &free_list);
+               rpci->pipelen = 0;
+       }
+       spin_unlock(&inode->i_lock);
+       rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
 }
 
 int
@@ -78,7 +81,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
        struct rpc_inode *rpci = RPC_I(inode);
        int res = -EPIPE;
 
-       down(&inode->i_sem);
+       spin_lock(&inode->i_lock);
        if (rpci->ops == NULL)
                goto out;
        if (rpci->nreaders) {
@@ -87,14 +90,15 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
                res = 0;
        } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
                if (list_empty(&rpci->pipe))
-                       schedule_delayed_work(&rpci->queue_timeout,
+                       queue_delayed_work(rpciod_workqueue,
+                                       &rpci->queue_timeout,
                                        RPC_UPCALL_TIMEOUT);
                list_add_tail(&msg->list, &rpci->pipe);
                rpci->pipelen += msg->len;
                res = 0;
        }
 out:
-       up(&inode->i_sem);
+       spin_unlock(&inode->i_lock);
        wake_up(&rpci->waitq);
        return res;
 }
@@ -109,20 +113,29 @@ static void
 rpc_close_pipes(struct inode *inode)
 {
        struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe_ops *ops;
 
-       cancel_delayed_work(&rpci->queue_timeout);
-       flush_scheduled_work();
-       down(&inode->i_sem);
-       if (rpci->ops != NULL) {
+       mutex_lock(&inode->i_mutex);
+       ops = rpci->ops;
+       if (ops != NULL) {
+               LIST_HEAD(free_list);
+
+               spin_lock(&inode->i_lock);
                rpci->nreaders = 0;
-               __rpc_purge_upcall(inode, -EPIPE);
-               rpci->nwriters = 0;
-               if (rpci->ops->release_pipe)
-                       rpci->ops->release_pipe(inode);
+               list_splice_init(&rpci->in_upcall, &free_list);
+               list_splice_init(&rpci->pipe, &free_list);
+               rpci->pipelen = 0;
                rpci->ops = NULL;
+               spin_unlock(&inode->i_lock);
+               rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE);
+               rpci->nwriters = 0;
+               if (ops->release_pipe)
+                       ops->release_pipe(inode);
+               cancel_delayed_work(&rpci->queue_timeout);
+               flush_workqueue(rpciod_workqueue);
        }
        rpc_inode_setowner(inode, NULL);
-       up(&inode->i_sem);
+       mutex_unlock(&inode->i_mutex);
 }
 
 static struct inode *
@@ -147,7 +160,7 @@ rpc_pipe_open(struct inode *inode, struct file *filp)
        struct rpc_inode *rpci = RPC_I(inode);
        int res = -ENXIO;
 
-       down(&inode->i_sem);
+       mutex_lock(&inode->i_mutex);
        if (rpci->ops != NULL) {
                if (filp->f_mode & FMODE_READ)
                        rpci->nreaders ++;
@@ -155,35 +168,45 @@ rpc_pipe_open(struct inode *inode, struct file *filp)
                        rpci->nwriters ++;
                res = 0;
        }
-       up(&inode->i_sem);
+       mutex_unlock(&inode->i_mutex);
        return res;
 }
 
 static int
 rpc_pipe_release(struct inode *inode, struct file *filp)
 {
-       struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
+       struct rpc_inode *rpci = RPC_I(inode);
        struct rpc_pipe_msg *msg;
 
-       down(&inode->i_sem);
+       mutex_lock(&inode->i_mutex);
        if (rpci->ops == NULL)
                goto out;
        msg = (struct rpc_pipe_msg *)filp->private_data;
        if (msg != NULL) {
-               msg->errno = -EPIPE;
-               list_del_init(&msg->list);
+               spin_lock(&inode->i_lock);
+               msg->errno = -EAGAIN;
+               list_del(&msg->list);
+               spin_unlock(&inode->i_lock);
                rpci->ops->destroy_msg(msg);
        }
        if (filp->f_mode & FMODE_WRITE)
                rpci->nwriters --;
-       if (filp->f_mode & FMODE_READ)
+       if (filp->f_mode & FMODE_READ) {
                rpci->nreaders --;
-       if (!rpci->nreaders)
-               __rpc_purge_upcall(inode, -EPIPE);
+               if (rpci->nreaders == 0) {
+                       LIST_HEAD(free_list);
+                       spin_lock(&inode->i_lock);
+                       list_splice_init(&rpci->pipe, &free_list);
+                       rpci->pipelen = 0;
+                       spin_unlock(&inode->i_lock);
+                       rpc_purge_list(rpci, &free_list,
+                                       rpci->ops->destroy_msg, -EAGAIN);
+               }
+       }
        if (rpci->ops->release_pipe)
                rpci->ops->release_pipe(inode);
 out:
-       up(&inode->i_sem);
+       mutex_unlock(&inode->i_mutex);
        return 0;
 }
 
@@ -195,13 +218,14 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
        struct rpc_pipe_msg *msg;
        int res = 0;
 
-       down(&inode->i_sem);
+       mutex_lock(&inode->i_mutex);
        if (rpci->ops == NULL) {
                res = -EPIPE;
                goto out_unlock;
        }
        msg = filp->private_data;
        if (msg == NULL) {
+               spin_lock(&inode->i_lock);
                if (!list_empty(&rpci->pipe)) {
                        msg = list_entry(rpci->pipe.next,
                                        struct rpc_pipe_msg,
@@ -211,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
                        filp->private_data = msg;
                        msg->copied = 0;
                }
+               spin_unlock(&inode->i_lock);
                if (msg == NULL)
                        goto out_unlock;
        }
@@ -218,11 +243,13 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
        res = rpci->ops->upcall(filp, msg, buf, len);
        if (res < 0 || msg->len == msg->copied) {
                filp->private_data = NULL;
-               list_del_init(&msg->list);
+               spin_lock(&inode->i_lock);
+               list_del(&msg->list);
+               spin_unlock(&inode->i_lock);
                rpci->ops->destroy_msg(msg);
        }
 out_unlock:
-       up(&inode->i_sem);
+       mutex_unlock(&inode->i_mutex);
        return res;
 }
 
@@ -233,11 +260,11 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of
        struct rpc_inode *rpci = RPC_I(inode);
        int res;
 
-       down(&inode->i_sem);
+       mutex_lock(&inode->i_mutex);
        res = -EPIPE;
        if (rpci->ops != NULL)
                res = rpci->ops->downcall(filp, buf, len);
-       up(&inode->i_sem);
+       mutex_unlock(&inode->i_mutex);
        return res;
 }
 
@@ -300,10 +327,8 @@ rpc_show_info(struct seq_file *m, void *v)
        seq_printf(m, "RPC server: %s\n", clnt->cl_server);
        seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
                        clnt->cl_prog, clnt->cl_vers);
-       seq_printf(m, "address: %u.%u.%u.%u\n",
-                       NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr));
-       seq_printf(m, "protocol: %s\n",
-                       clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
+       seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
+       seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
        return 0;
 }
 
@@ -315,7 +340,7 @@ rpc_info_open(struct inode *inode, struct file *file)
 
        if (!ret) {
                struct seq_file *m = file->private_data;
-               down(&inode->i_sem);
+               mutex_lock(&inode->i_mutex);
                clnt = RPC_I(inode)->private;
                if (clnt) {
                        atomic_inc(&clnt->cl_users);
@@ -324,7 +349,7 @@ rpc_info_open(struct inode *inode, struct file *file)
                        single_release(inode, file);
                        ret = -EINVAL;
                }
-               up(&inode->i_sem);
+               mutex_unlock(&inode->i_mutex);
        }
        return ret;
 }
@@ -367,7 +392,7 @@ enum {
  */
 struct rpc_filelist {
        char *name;
-       struct file_operations *i_fop;
+       const struct file_operations *i_fop;
        int mode;
 };
 
@@ -407,14 +432,17 @@ static struct rpc_filelist authfiles[] = {
        },
 };
 
-static int
-rpc_get_mount(void)
+struct vfsmount *rpc_get_mount(void)
 {
-       return simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
+       int err;
+
+       err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count);
+       if (err != 0)
+               return ERR_PTR(err);
+       return rpc_mount;
 }
 
-static void
-rpc_put_mount(void)
+void rpc_put_mount(void)
 {
        simple_release_fs(&rpc_mount, &rpc_mount_count);
 }
@@ -424,12 +452,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd)
 {
        if (path[0] == '\0')
                return -ENOENT;
-       if (rpc_get_mount()) {
+       nd->mnt = rpc_get_mount();
+       if (IS_ERR(nd->mnt)) {
                printk(KERN_WARNING "%s: %s failed to mount "
                               "pseudofilesystem \n", __FILE__, __FUNCTION__);
-               return -ENODEV;
+               return PTR_ERR(nd->mnt);
        }
-       nd->mnt = mntget(rpc_mount);
+       mntget(nd->mnt);
        nd->dentry = dget(rpc_mount->mnt_root);
        nd->last_type = LAST_ROOT;
        nd->flags = LOOKUP_PARENT;
@@ -459,14 +488,13 @@ rpc_get_inode(struct super_block *sb, int mode)
                return NULL;
        inode->i_mode = mode;
        inode->i_uid = inode->i_gid = 0;
-       inode->i_blksize = PAGE_CACHE_SIZE;
        inode->i_blocks = 0;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        switch(mode & S_IFMT) {
                case S_IFDIR:
                        inode->i_fop = &simple_dir_operations;
                        inode->i_op = &simple_dir_inode_operations;
-                       inode->i_nlink++;
+                       inc_nlink(inode);
                default:
                        break;
        }
@@ -484,11 +512,11 @@ rpc_depopulate(struct dentry *parent)
        struct dentry *dentry, *dvec[10];
        int n = 0;
 
-       down(&dir->i_sem);
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
 repeat:
        spin_lock(&dcache_lock);
        list_for_each_safe(pos, next, &parent->d_subdirs) {
-               dentry = list_entry(pos, struct dentry, d_child);
+               dentry = list_entry(pos, struct dentry, d_u.d_child);
                spin_lock(&dentry->d_lock);
                if (!d_unhashed(dentry)) {
                        dget_locked(dentry);
@@ -508,11 +536,12 @@ repeat:
                                rpc_close_pipes(dentry->d_inode);
                                simple_unlink(dir, dentry);
                        }
+                       inode_dir_notify(dir, DN_DELETE);
                        dput(dentry);
                } while (n);
                goto repeat;
        }
-       up(&dir->i_sem);
+       mutex_unlock(&dir->i_mutex);
 }
 
 static int
@@ -525,7 +554,7 @@ rpc_populate(struct dentry *parent,
        struct dentry *dentry;
        int mode, i;
 
-       down(&dir->i_sem);
+       mutex_lock(&dir->i_mutex);
        for (i = start; i < eof; i++) {
                dentry = d_alloc_name(parent, files[i].name);
                if (!dentry)
@@ -542,13 +571,13 @@ rpc_populate(struct dentry *parent,
                if (private)
                        rpc_inode_setowner(inode, private);
                if (S_ISDIR(mode))
-                       dir->i_nlink++;
+                       inc_nlink(dir);
                d_add(dentry, inode);
        }
-       up(&dir->i_sem);
+       mutex_unlock(&dir->i_mutex);
        return 0;
 out_bad:
-       up(&dir->i_sem);
+       mutex_unlock(&dir->i_mutex);
        printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
                        __FILE__, __FUNCTION__, parent->d_name.name);
        return -ENOMEM;
@@ -564,9 +593,8 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
                goto out_err;
        inode->i_ino = iunique(dir->i_sb, 100);
        d_instantiate(dentry, inode);
-       dir->i_nlink++;
+       inc_nlink(dir);
        inode_dir_notify(dir, DN_CREATE);
-       rpc_get_mount();
        return 0;
 out_err:
        printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
@@ -580,30 +608,25 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
        int error;
 
        shrink_dcache_parent(dentry);
-       if (dentry->d_inode)
-               rpc_close_pipes(dentry->d_inode);
+       if (d_unhashed(dentry))
+               return 0;
        if ((error = simple_rmdir(dir, dentry)) != 0)
                return error;
        if (!error) {
                inode_dir_notify(dir, DN_DELETE);
                d_drop(dentry);
-               rpc_put_mount();
        }
        return 0;
 }
 
 static struct dentry *
-rpc_lookup_negative(char *path, struct nameidata *nd)
+rpc_lookup_create(struct dentry *parent, const char *name, int len)
 {
+       struct inode *dir = parent->d_inode;
        struct dentry *dentry;
-       struct inode *dir;
-       int error;
 
-       if ((error = rpc_lookup_parent(path, nd)) != 0)
-               return ERR_PTR(error);
-       dir = nd->dentry->d_inode;
-       down(&dir->i_sem);
-       dentry = lookup_hash(nd);
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       dentry = lookup_one_len(name, parent, len);
        if (IS_ERR(dentry))
                goto out_err;
        if (dentry->d_inode) {
@@ -613,8 +636,21 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
        }
        return dentry;
 out_err:
-       up(&dir->i_sem);
-       rpc_release_path(nd);
+       mutex_unlock(&dir->i_mutex);
+       return dentry;
+}
+
+static struct dentry *
+rpc_lookup_negative(char *path, struct nameidata *nd)
+{
+       struct dentry *dentry;
+       int error;
+
+       if ((error = rpc_lookup_parent(path, nd)) != 0)
+               return ERR_PTR(error);
+       dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len);
+       if (IS_ERR(dentry))
+               rpc_release_path(nd);
        return dentry;
 }
 
@@ -638,8 +674,9 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
                        RPCAUTH_info, RPCAUTH_EOF);
        if (error)
                goto err_depopulate;
+       dget(dentry);
 out:
-       up(&dir->i_sem);
+       mutex_unlock(&dir->i_mutex);
        rpc_release_path(&nd);
        return dentry;
 err_depopulate:
@@ -654,44 +691,35 @@ err_dput:
 }
 
 int
-rpc_rmdir(char *path)
+rpc_rmdir(struct dentry *dentry)
 {
-       struct nameidata nd;
-       struct dentry *dentry;
+       struct dentry *parent;
        struct inode *dir;
        int error;
 
-       if ((error = rpc_lookup_parent(path, &nd)) != 0)
-               return error;
-       dir = nd.dentry->d_inode;
-       down(&dir->i_sem);
-       dentry = lookup_hash(&nd);
-       if (IS_ERR(dentry)) {
-               error = PTR_ERR(dentry);
-               goto out_release;
-       }
+       parent = dget_parent(dentry);
+       dir = parent->d_inode;
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
        rpc_depopulate(dentry);
        error = __rpc_rmdir(dir, dentry);
        dput(dentry);
-out_release:
-       up(&dir->i_sem);
-       rpc_release_path(&nd);
+       mutex_unlock(&dir->i_mutex);
+       dput(parent);
        return error;
 }
 
 struct dentry *
-rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
+rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags)
 {
-       struct nameidata nd;
        struct dentry *dentry;
        struct inode *dir, *inode;
        struct rpc_inode *rpci;
 
-       dentry = rpc_lookup_negative(path, &nd);
+       dentry = rpc_lookup_create(parent, name, strlen(name));
        if (IS_ERR(dentry))
                return dentry;
-       dir = nd.dentry->d_inode;
-       inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR);
+       dir = parent->d_inode;
+       inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR);
        if (!inode)
                goto err_dput;
        inode->i_ino = iunique(dir->i_sb, 100);
@@ -702,45 +730,40 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
        rpci->flags = flags;
        rpci->ops = ops;
        inode_dir_notify(dir, DN_CREATE);
+       dget(dentry);
 out:
-       up(&dir->i_sem);
-       rpc_release_path(&nd);
+       mutex_unlock(&dir->i_mutex);
        return dentry;
 err_dput:
        dput(dentry);
        dentry = ERR_PTR(-ENOMEM);
-       printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n",
-                       __FILE__, __FUNCTION__, path, -ENOMEM);
+       printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
+                       __FILE__, __FUNCTION__, parent->d_name.name, name,
+                       -ENOMEM);
        goto out;
 }
 
 int
-rpc_unlink(char *path)
+rpc_unlink(struct dentry *dentry)
 {
-       struct nameidata nd;
-       struct dentry *dentry;
+       struct dentry *parent;
        struct inode *dir;
-       int error;
+       int error = 0;
 
-       if ((error = rpc_lookup_parent(path, &nd)) != 0)
-               return error;
-       dir = nd.dentry->d_inode;
-       down(&dir->i_sem);
-       dentry = lookup_hash(&nd);
-       if (IS_ERR(dentry)) {
-               error = PTR_ERR(dentry);
-               goto out_release;
-       }
-       d_drop(dentry);
-       if (dentry->d_inode) {
-               rpc_close_pipes(dentry->d_inode);
-               error = simple_unlink(dir, dentry);
+       parent = dget_parent(dentry);
+       dir = parent->d_inode;
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       if (!d_unhashed(dentry)) {
+               d_drop(dentry);
+               if (dentry->d_inode) {
+                       rpc_close_pipes(dentry->d_inode);
+                       error = simple_unlink(dir, dentry);
+               }
+               inode_dir_notify(dir, DN_DELETE);
        }
        dput(dentry);
-       inode_dir_notify(dir, DN_DELETE);
-out_release:
-       up(&dir->i_sem);
-       rpc_release_path(&nd);
+       mutex_unlock(&dir->i_mutex);
+       dput(parent);
        return error;
 }
 
@@ -785,11 +808,11 @@ out:
        return -ENOMEM;
 }
 
-static struct super_block *
+static int
 rpc_get_sb(struct file_system_type *fs_type,
-               int flags, const char *dev_name, void *data)
+               int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       return get_sb_single(fs_type, flags, data, rpc_fill_super);
+       return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt);
 }
 
 static struct file_system_type rpc_pipe_fs_type = {
@@ -822,9 +845,10 @@ init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 int register_rpc_pipefs(void)
 {
        rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
-                                             sizeof(struct rpc_inode),
-                                             0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
-                                             init_once, NULL);
+                               sizeof(struct rpc_inode),
+                               0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
+                                               SLAB_MEM_SPREAD),
+                               init_once, NULL);
        if (!rpc_inode_cachep)
                return -ENOMEM;
        register_filesystem(&rpc_pipe_fs_type);
@@ -833,7 +857,6 @@ int register_rpc_pipefs(void)
 
 void unregister_rpc_pipefs(void)
 {
-       if (kmem_cache_destroy(rpc_inode_cachep))
-               printk(KERN_WARNING "RPC: unable to free inode cache\n");
+       kmem_cache_destroy(rpc_inode_cachep);
        unregister_filesystem(&rpc_pipe_fs_type);
 }