linux/fs/nfs/cache_lib.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfs/cache_lib.c
   3 *
   4 * Helper routines for the NFS client caches
   5 *
   6 * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com>
   7 */
   8#include <linux/kmod.h>
   9#include <linux/module.h>
  10#include <linux/moduleparam.h>
  11#include <linux/mount.h>
  12#include <linux/namei.h>
  13#include <linux/sunrpc/cache.h>
  14#include <linux/sunrpc/rpc_pipe_fs.h>
  15
  16#include "cache_lib.h"
  17
  18#define NFS_CACHE_UPCALL_PATHLEN 256
  19#define NFS_CACHE_UPCALL_TIMEOUT 15
  20
  21static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN] =
  22                                "/sbin/nfs_cache_getent";
  23static unsigned long nfs_cache_getent_timeout = NFS_CACHE_UPCALL_TIMEOUT;
  24
  25module_param_string(cache_getent, nfs_cache_getent_prog,
  26                sizeof(nfs_cache_getent_prog), 0600);
  27MODULE_PARM_DESC(cache_getent, "Path to the client cache upcall program");
  28module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, ulong, 0600);
  29MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which "
  30                "the cache upcall is assumed to have failed");
  31
  32int nfs_cache_upcall(struct cache_detail *cd, char *entry_name)
  33{
  34        static char *envp[] = { "HOME=/",
  35                "TERM=linux",
  36                "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
  37                NULL
  38        };
  39        char *argv[] = {
  40                nfs_cache_getent_prog,
  41                cd->name,
  42                entry_name,
  43                NULL
  44        };
  45        int ret = -EACCES;
  46
  47        if (nfs_cache_getent_prog[0] == '\0')
  48                goto out;
  49        ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
  50        /*
  51         * Disable the upcall mechanism if we're getting an ENOENT or
  52         * EACCES error. The admin can re-enable it on the fly by using
  53         * sysfs to set the 'cache_getent' parameter once the problem
  54         * has been fixed.
  55         */
  56        if (ret == -ENOENT || ret == -EACCES)
  57                nfs_cache_getent_prog[0] = '\0';
  58out:
  59        return ret > 0 ? 0 : ret;
  60}
  61
  62/*
  63 * Deferred request handling
  64 */
  65void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq)
  66{
  67        if (atomic_dec_and_test(&dreq->count))
  68                kfree(dreq);
  69}
  70
  71static void nfs_dns_cache_revisit(struct cache_deferred_req *d, int toomany)
  72{
  73        struct nfs_cache_defer_req *dreq;
  74
  75        dreq = container_of(d, struct nfs_cache_defer_req, deferred_req);
  76
  77        complete_all(&dreq->completion);
  78        nfs_cache_defer_req_put(dreq);
  79}
  80
  81static struct cache_deferred_req *nfs_dns_cache_defer(struct cache_req *req)
  82{
  83        struct nfs_cache_defer_req *dreq;
  84
  85        dreq = container_of(req, struct nfs_cache_defer_req, req);
  86        dreq->deferred_req.revisit = nfs_dns_cache_revisit;
  87        atomic_inc(&dreq->count);
  88
  89        return &dreq->deferred_req;
  90}
  91
  92struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void)
  93{
  94        struct nfs_cache_defer_req *dreq;
  95
  96        dreq = kzalloc(sizeof(*dreq), GFP_KERNEL);
  97        if (dreq) {
  98                init_completion(&dreq->completion);
  99                atomic_set(&dreq->count, 1);
 100                dreq->req.defer = nfs_dns_cache_defer;
 101        }
 102        return dreq;
 103}
 104
 105int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq)
 106{
 107        if (wait_for_completion_timeout(&dreq->completion,
 108                        nfs_cache_getent_timeout * HZ) == 0)
 109                return -ETIMEDOUT;
 110        return 0;
 111}
 112
 113int nfs_cache_register(struct cache_detail *cd)
 114{
 115        struct nameidata nd;
 116        struct vfsmount *mnt;
 117        int ret;
 118
 119        mnt = rpc_get_mount();
 120        if (IS_ERR(mnt))
 121                return PTR_ERR(mnt);
 122        ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd);
 123        if (ret)
 124                goto err;
 125        ret = sunrpc_cache_register_pipefs(nd.path.dentry,
 126                        cd->name, 0600, cd);
 127        path_put(&nd.path);
 128        if (!ret)
 129                return ret;
 130err:
 131        rpc_put_mount();
 132        return ret;
 133}
 134
 135void nfs_cache_unregister(struct cache_detail *cd)
 136{
 137        sunrpc_cache_unregister_pipefs(cd);
 138        rpc_put_mount();
 139}
 140
 141