vsprintf: factor out skip_space code in a separate function
[safe/jmp/linux-2.6] / net / sunrpc / rpc_pipe.c
index 2a4e6eb..49278f8 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
+#include <linux/sunrpc/cache.h>
 
 static struct vfsmount *rpc_mount __read_mostly;
 static int rpc_mount_count;
@@ -406,19 +407,6 @@ struct rpc_filelist {
        umode_t mode;
 };
 
-enum {
-       RPCAUTH_info,
-       RPCAUTH_EOF
-};
-
-static const struct rpc_filelist authfiles[] = {
-       [RPCAUTH_info] = {
-               .name = "info",
-               .i_fop = &rpc_info_operations,
-               .mode = S_IFREG | S_IRUSR,
-       },
-};
-
 struct vfsmount *rpc_get_mount(void)
 {
        int err;
@@ -428,11 +416,13 @@ struct vfsmount *rpc_get_mount(void)
                return ERR_PTR(err);
        return rpc_mount;
 }
+EXPORT_SYMBOL_GPL(rpc_get_mount);
 
 void rpc_put_mount(void)
 {
        simple_release_fs(&rpc_mount, &rpc_mount_count);
 }
+EXPORT_SYMBOL_GPL(rpc_put_mount);
 
 static int rpc_delete_dentry(struct dentry *dentry)
 {
@@ -443,42 +433,6 @@ static const struct dentry_operations rpc_dentry_operations = {
        .d_delete = rpc_delete_dentry,
 };
 
-static int __rpc_lookup_path(const char *pathname, unsigned flags,
-                            struct nameidata *nd)
-{
-       struct vfsmount *mnt;
-
-       if (pathname[0] == '\0')
-               return -ENOENT;
-
-       mnt = rpc_get_mount();
-       if (IS_ERR(mnt)) {
-               printk(KERN_WARNING "%s: %s failed to mount "
-                              "pseudofilesystem \n", __FILE__, __func__);
-               return PTR_ERR(mnt);
-       }
-
-       if (vfs_path_lookup(mnt->mnt_root, mnt, pathname, flags, nd)) {
-               printk(KERN_WARNING "%s: %s failed to find path %s\n",
-                               __FILE__, __func__, pathname);
-               rpc_put_mount();
-               return -ENOENT;
-       }
-       return 0;
-}
-
-static int rpc_lookup_parent(const char *pathname, struct nameidata *nd)
-{
-       return __rpc_lookup_path(pathname, LOOKUP_PARENT, nd);
-}
-
-static void
-rpc_release_path(struct nameidata *nd)
-{
-       path_put(&nd->path);
-       rpc_put_mount();
-}
-
 static struct inode *
 rpc_get_inode(struct super_block *sb, umode_t mode)
 {
@@ -639,26 +593,6 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
        return ERR_PTR(-EEXIST);
 }
 
-static struct dentry *rpc_lookup_negative(const char *path,
-                                         struct nameidata *nd)
-{
-       struct inode *dir;
-       struct dentry *dentry;
-       int error;
-
-       error = rpc_lookup_parent(path, nd);
-       if (error != 0)
-               return ERR_PTR(error);
-       dir = nd->path.dentry->d_inode;
-       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       dentry = __rpc_lookup_create_exclusive(nd->path.dentry, &nd->last);
-       if (IS_ERR(dentry)) {
-               mutex_unlock(&dir->i_mutex);
-               rpc_release_path(nd);
-       }
-       return dentry;
-}
-
 /*
  * FIXME: This probably has races.
  */
@@ -754,54 +688,38 @@ out_bad:
        return err;
 }
 
-/**
- * rpc_mkdir - Create a new directory in rpc_pipefs
- * @path: path from the rpc_pipefs root to the new directory
- * @rpc_client: rpc client to associate with this directory
- *
- * This creates a directory at the given @path associated with
- * @rpc_clnt, which will contain a file named "info" with some basic
- * information about the client, together with any "pipes" that may
- * later be created using rpc_mkpipe().
- */
-struct dentry *
-rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
+static struct dentry *rpc_mkdir_populate(struct dentry *parent,
+               struct qstr *name, umode_t mode, void *private,
+               int (*populate)(struct dentry *, void *), void *args_populate)
 {
-       struct nameidata nd;
        struct dentry *dentry;
-       struct inode *dir;
+       struct inode *dir = parent->d_inode;
        int error;
 
-       dentry = rpc_lookup_negative(path, &nd);
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       dentry = __rpc_lookup_create_exclusive(parent, name);
        if (IS_ERR(dentry))
-               return dentry;
-       dir = nd.path.dentry->d_inode;
-       error = __rpc_mkdir(dir, dentry, S_IRUGO | S_IXUGO, NULL, rpc_client);
+               goto out;
+       error = __rpc_mkdir(dir, dentry, mode, NULL, private);
        if (error != 0)
                goto out_err;
-       error = rpc_populate(dentry, authfiles,
-                       RPCAUTH_info, RPCAUTH_EOF, rpc_client);
-       if (error)
-               goto err_rmdir;
+       if (populate != NULL) {
+               error = populate(dentry, args_populate);
+               if (error)
+                       goto err_rmdir;
+       }
 out:
        mutex_unlock(&dir->i_mutex);
-       rpc_release_path(&nd);
        return dentry;
 err_rmdir:
        __rpc_rmdir(dir, dentry);
 out_err:
-       printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
-                       __FILE__, __func__, path, error);
        dentry = ERR_PTR(error);
        goto out;
 }
 
-/**
- * rpc_rmdir - Remove a directory created with rpc_mkdir()
- * @dentry: directory to remove
- */
-int
-rpc_rmdir(struct dentry *dentry)
+static int rpc_rmdir_depopulate(struct dentry *dentry,
+               void (*depopulate)(struct dentry *))
 {
        struct dentry *parent;
        struct inode *dir;
@@ -810,7 +728,8 @@ rpc_rmdir(struct dentry *dentry)
        parent = dget_parent(dentry);
        dir = parent->d_inode;
        mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
+       if (depopulate != NULL)
+               depopulate(dentry);
        error = __rpc_rmdir(dir, dentry);
        mutex_unlock(&dir->i_mutex);
        dput(parent);
@@ -914,10 +833,105 @@ rpc_unlink(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(rpc_unlink);
 
+enum {
+       RPCAUTH_info,
+       RPCAUTH_EOF
+};
+
+static const struct rpc_filelist authfiles[] = {
+       [RPCAUTH_info] = {
+               .name = "info",
+               .i_fop = &rpc_info_operations,
+               .mode = S_IFREG | S_IRUSR,
+       },
+};
+
+static int rpc_clntdir_populate(struct dentry *dentry, void *private)
+{
+       return rpc_populate(dentry,
+                           authfiles, RPCAUTH_info, RPCAUTH_EOF,
+                           private);
+}
+
+static void rpc_clntdir_depopulate(struct dentry *dentry)
+{
+       rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
+}
+
+/**
+ * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
+ * @dentry: dentry from the rpc_pipefs root to the new directory
+ * @name: &struct qstr for the name
+ * @rpc_client: rpc client to associate with this directory
+ *
+ * This creates a directory at the given @path associated with
+ * @rpc_clnt, which will contain a file named "info" with some basic
+ * information about the client, together with any "pipes" that may
+ * later be created using rpc_mkpipe().
+ */
+struct dentry *rpc_create_client_dir(struct dentry *dentry,
+                                  struct qstr *name,
+                                  struct rpc_clnt *rpc_client)
+{
+       return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
+                       rpc_clntdir_populate, rpc_client);
+}
+
+/**
+ * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
+ * @dentry: directory to remove
+ */
+int rpc_remove_client_dir(struct dentry *dentry)
+{
+       return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
+}
+
+static const struct rpc_filelist cache_pipefs_files[3] = {
+       [0] = {
+               .name = "channel",
+               .i_fop = &cache_file_operations_pipefs,
+               .mode = S_IFREG|S_IRUSR|S_IWUSR,
+       },
+       [1] = {
+               .name = "content",
+               .i_fop = &content_file_operations_pipefs,
+               .mode = S_IFREG|S_IRUSR,
+       },
+       [2] = {
+               .name = "flush",
+               .i_fop = &cache_flush_operations_pipefs,
+               .mode = S_IFREG|S_IRUSR|S_IWUSR,
+       },
+};
+
+static int rpc_cachedir_populate(struct dentry *dentry, void *private)
+{
+       return rpc_populate(dentry,
+                           cache_pipefs_files, 0, 3,
+                           private);
+}
+
+static void rpc_cachedir_depopulate(struct dentry *dentry)
+{
+       rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
+}
+
+struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name,
+                                   mode_t umode, struct cache_detail *cd)
+{
+       return rpc_mkdir_populate(parent, name, umode, NULL,
+                       rpc_cachedir_populate, cd);
+}
+
+void rpc_remove_cache_dir(struct dentry *dentry)
+{
+       rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate);
+}
+
 /*
  * populate the filesystem
  */
-static struct super_operations s_ops = {
+static const struct super_operations s_ops = {
        .alloc_inode    = rpc_alloc_inode,
        .destroy_inode  = rpc_destroy_inode,
        .statfs         = simple_statfs,
@@ -935,6 +949,7 @@ enum {
        RPCAUTH_portmap,
        RPCAUTH_statd,
        RPCAUTH_nfsd4_cb,
+       RPCAUTH_cache,
        RPCAUTH_RootEOF
 };
 
@@ -963,6 +978,10 @@ static const struct rpc_filelist files[] = {
                .name = "nfsd4_cb",
                .mode = S_IFDIR | S_IRUGO | S_IXUGO,
        },
+       [RPCAUTH_cache] = {
+               .name = "cache",
+               .mode = S_IFDIR | S_IRUGO | S_IXUGO,
+       },
 };
 
 static int