patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / nfsd / nfs4idmap.c
index 97d430b..4ba5408 100644 (file)
@@ -175,6 +175,14 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
        return 0;
 }
 
+static void
+warn_no_idmapd(struct cache_detail *detail)
+{
+       printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n",
+                       detail->last_close? "died" : "not been started");
+}
+
+
 static int         idtoname_parse(struct cache_detail *, char *, int);
 static struct ent *idtoname_lookup(struct ent *, int);
 
@@ -186,6 +194,7 @@ struct cache_detail idtoname_cache = {
        .cache_request  = idtoname_request,
        .cache_parse    = idtoname_parse,
        .cache_show     = idtoname_show,
+       .warn_no_listener = warn_no_idmapd,
 };
 
 int
@@ -318,6 +327,7 @@ struct cache_detail nametoid_cache = {
        .cache_request  = nametoid_request,
        .cache_parse    = nametoid_parse,
        .cache_show     = nametoid_show,
+       .warn_no_listener = warn_no_idmapd,
 };
 
 int
@@ -409,13 +419,19 @@ struct idmap_defer_req {
        atomic_t                        count;
 };
 
-static void
+static inline void
 put_mdr(struct idmap_defer_req *mdr)
 {
        if (atomic_dec_and_test(&mdr->count))
                kfree(mdr);
 }
 
+static inline void
+get_mdr(struct idmap_defer_req *mdr)
+{
+       atomic_inc(&mdr->count);
+}
+
 static void
 idmap_revisit(struct cache_deferred_req *dreq, int toomany)
 {
@@ -433,31 +449,44 @@ idmap_defer(struct cache_req *req)
                container_of(req, struct idmap_defer_req, req);
 
        mdr->deferred_req.revisit = idmap_revisit;
+       get_mdr(mdr);
        return (&mdr->deferred_req);
 }
 
-static int threads_waiting = 0;
+static inline int
+do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
+               struct cache_detail *detail, struct ent **item,
+               struct idmap_defer_req *mdr)
+{
+       *item = lookup_fn(key, 0);
+       if (!*item)
+               return -ENOMEM;
+       return cache_check(detail, &(*item)->h, &mdr->req);
+}
 
 static inline int
-idmap_lookup_wait(struct idmap_defer_req *mdr, wait_queue_t waitq, struct
-               svc_rqst *rqstp) {
-       int ret = -ETIMEDOUT;
-
-       set_task_state(current, TASK_INTERRUPTIBLE);
-       lock_kernel();
-       /* XXX: Does it matter that threads_waiting isn't per-server? */
-       /* Note: BKL prevents races with nfsd_svc and other lookups */
-       if (2 * threads_waiting > rqstp->rq_server->sv_nrthreads)
-               goto out;
-       threads_waiting++;
-       schedule_timeout(10 * HZ);
-       threads_waiting--;
-       ret = 0;
-out:
-       unlock_kernel();
-       remove_wait_queue(&mdr->waitq, &waitq);
-       set_task_state(current, TASK_RUNNING);
-       put_mdr(mdr);
+do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int),
+                       struct ent *key, struct cache_detail *detail,
+                       struct ent **item)
+{
+       int ret = -ENOMEM;
+
+       *item = lookup_fn(key, 0);
+       if (!*item)
+               goto out_err;
+       ret = -ETIMEDOUT;
+       if (!test_bit(CACHE_VALID, &(*item)->h.flags)
+                       || (*item)->h.expiry_time < get_seconds()
+                       || detail->flush_time > (*item)->h.last_refresh)
+               goto out_put;
+       ret = -ENOENT;
+       if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
+               goto out_put;
+       return 0;
+out_put:
+       ent_put(&(*item)->h, detail);
+out_err:
+       *item = NULL;
        return ret;
 }
 
@@ -467,36 +496,22 @@ idmap_lookup(struct svc_rqst *rqstp,
                struct cache_detail *detail, struct ent **item)
 {
        struct idmap_defer_req *mdr;
-       DECLARE_WAITQUEUE(waitq, current);
        int ret;
 
-       *item = lookup_fn(key, 0);
-       if (!*item)
-               return -ENOMEM;
        mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
+       if (!mdr)
+               return -ENOMEM;
        memset(mdr, 0, sizeof(*mdr));
+       atomic_set(&mdr->count, 1);
        init_waitqueue_head(&mdr->waitq);
-       add_wait_queue(&mdr->waitq, &waitq);
-       atomic_set(&mdr->count, 2);
        mdr->req.defer = idmap_defer;
-       ret = cache_check(detail, &(*item)->h, &mdr->req);
+       ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr);
        if (ret == -EAGAIN) {
-               ret = idmap_lookup_wait(mdr, waitq, rqstp);
-               if (ret)
-                       goto out;
-               /* Try again, but don't wait. */
-               *item = lookup_fn(key, 0);
-               ret = -ENOMEM;
-               if (!*item)
-                       goto out;
-               ret = -ETIMEDOUT;
-               if (!test_bit(CACHE_VALID, &(*item)->h.flags)) {
-                       ent_put(&(*item)->h, detail);
-                       goto out;
-               }
-               ret = cache_check(detail, &(*item)->h, NULL);
+               wait_event_interruptible_timeout(mdr->waitq,
+                       test_bit(CACHE_VALID, &(*item)->h.flags), 1 * HZ);
+               ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item);
        }
-out:
+       put_mdr(mdr);
        return ret;
 }
 
@@ -515,6 +530,8 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
        key.name[namelen] = '\0';
        strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
        ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
+       if (ret == -ENOENT)
+               ret = -ESRCH; /* nfserr_badname */
        if (ret)
                return ret;
        *id = item->id;
@@ -533,6 +550,8 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
 
        strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
        ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
+       if (ret == -ENOENT)
+               return sprintf(name, "%u", id);
        if (ret)
                return ret;
        ret = strlen(item->name);