CTC++ Coverage Report - Execution Profile    #951/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: fs/lockd/clntproc.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/442)

Start/ End/    
True False - Line Source

  1 /*
  2  * linux/fs/lockd/clntproc.c
  3  *
  4  * RPC procedures for the client side NLM implementation
  5  *
  6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  7  */
  8 
  9 #include <linux/config.h>
  10 #include <linux/module.h>
  11 #include <linux/types.h>
  12 #include <linux/errno.h>
  13 #include <linux/fs.h>
  14 #include <linux/nfs_fs.h>
  15 #include <linux/utsname.h>
  16 #include <linux/smp_lock.h>
  17 #include <linux/sunrpc/clnt.h>
  18 #include <linux/sunrpc/svc.h>
  19 #include <linux/lockd/lockd.h>
  20 #include <linux/lockd/sm_inter.h>
  21 
  22 #define NLMDBG_FACILITY      NLMDBG_CLIENT
  23 #define NLMCLNT_GRACE_WAIT   (5*HZ)
  24 #define NLMCLNT_POLL_TIMEOUT   (30*HZ)
  25 #define NLMCLNT_MAX_RETRIES   3
  26 
  27 static int   nlmclnt_test(struct nlm_rqst *, struct file_lock *);
  28 static int   nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
  29 static int   nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
  30 static int   nlm_stat_to_errno(u32 stat);
  31 static void   nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
  32 static int   nlmclnt_cancel(struct nlm_host *, int , struct file_lock *);
  33 
  34 static const struct rpc_call_ops nlmclnt_unlock_ops;
  35 static const struct rpc_call_ops nlmclnt_cancel_ops;
  36 
  37 /*
  38  * Cookie counter for NLM requests
  39  */
  40 static u32   nlm_cookie = 0x1234;
  41 
 
- 42 static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
  43 {
  44    memcpy(c->data, &nlm_cookie, 4);
  45    memset(c->data+4, 0, 4);
  46    c->len=4;
  47    nlm_cookie++;
  48 }
  49 
 
- 50 static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
  51 {
  52    atomic_inc(&lockowner->count);
 - 53    return lockowner;
  54 }
  55 
 
- 56 static void nlm_put_lockowner(struct nlm_lockowner *lockowner)
  57 {
- 58    if (!atomic_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
 - 59       return;
  60    list_del(&lockowner->list);
    61    spin_unlock(&lockowner->host->h_lock);
    61   do
- 61   do-while (0)
- 61 do-while (0)
  62    nlm_release_host(lockowner->host);
  63    kfree(lockowner);
  64 }
  65 
 
- 66 static inline int nlm_pidbusy(struct nlm_host *host, uint32_t pid)
  67 {
  68    struct nlm_lockowner *lockowner;
- 69    list_for_each_entry(lockowner, &host->h_lockowners, list) {
- 70       if (lockowner->pid == pid)
 - 71          return -EBUSY;
  72    }
 - 73    return 0;
  74 }
  75 
 
- 76 static inline uint32_t __nlm_alloc_pid(struct nlm_host *host)
  77 {
  78    uint32_t res;
    79    do {
  80       res = host->h_pidcount++;
- 81    } while (nlm_pidbusy(host, res) < 0);
 - 82    return res;
  83 }
  84 
 
- 85 static struct nlm_lockowner *__nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner)
  86 {
  87    struct nlm_lockowner *lockowner;
- 88    list_for_each_entry(lockowner, &host->h_lockowners, list) {
- 89       if (lockowner->owner != owner)
 - 90          continue;
 - 91       return nlm_get_lockowner(lockowner);
  92    }
 - 93    return NULL;
  94 }
  95 
 
- 96 static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner)
  97 {
  98    struct nlm_lockowner *res, *new = NULL;
  99 
    100    spin_lock(&host->h_lock);
    100   do
- 100   do-while (0)
- 100 do-while (0)
  101    res = __nlm_find_lockowner(host, owner);
- 102    if (res == NULL) {
    103       spin_unlock(&host->h_lock);
    103     do
- 103     do-while (0)
- 103   do-while (0)
  104       new = (struct nlm_lockowner *)kmalloc(sizeof(*new), GFP_KERNEL);
    105       spin_lock(&host->h_lock);
    105     do
- 105     do-while (0)
- 105   do-while (0)
  106       res = __nlm_find_lockowner(host, owner);
- 107       if (res == NULL && new != NULL) {
 - 107     T && T
 - 107     T && F
 - 107     F && _
  108          res = new;
  109          atomic_set(&new->count, 1);
  110          new->owner = owner;
  111          new->pid = __nlm_alloc_pid(host);
  112          new->host = nlm_get_host(host);
  113          list_add(&new->list, &host->h_lockowners);
  114          new = NULL;
  115       }
  116    }
    117    spin_unlock(&host->h_lock);
    117   do
- 117   do-while (0)
- 117 do-while (0)
  118    kfree(new);
 - 119    return res;
  120 }
  121 
  122 /*
  123  * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls
  124  */
 
- 125 static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
  126 {
  127    struct nlm_args   *argp = &req->a_args;
  128    struct nlm_lock   *lock = &argp->lock;
  129 
  130    nlmclnt_next_cookie(&argp->cookie);
  131    argp->state   = nsm_local_state;
  132    memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
  133    lock->caller  = system_utsname.nodename;
  134    lock->oh.data = req->a_owner;
  135    lock->oh.len  = sprintf(req->a_owner, "%d@%s",
  136             current->pid, system_utsname.nodename);
  137    locks_copy_lock(&lock->fl, fl);
  138 }
  139 
 
- 140 static void nlmclnt_release_lockargs(struct nlm_rqst *req)
  141 {
  142    struct file_lock *fl = &req->a_args.lock.fl;
  143 
- 144    if (fl->fl_ops && fl->fl_ops->fl_release_private)
 - 144   T && T
 - 144   T && F
 - 144   F && _
  145       fl->fl_ops->fl_release_private(fl);
  146 }
  147 
  148 /*
  149  * Initialize arguments for GRANTED call. The nlm_rqst structure
  150  * has been cleared already.
  151  */
  152 int
 
- 153 nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
  154 {
  155    locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
  156    memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
  157    call->a_args.lock.caller = system_utsname.nodename;
  158    call->a_args.lock.oh.len = lock->oh.len;
  159 
  160    /* set default data area */
  161    call->a_args.lock.oh.data = call->a_owner;
  162 
- 163    if (lock->oh.len > NLMCLNT_OHSIZE) {
  164       void *data = kmalloc(lock->oh.len, GFP_KERNEL);
- 165       if (!data) {
  166          nlmclnt_freegrantargs(call);
 - 167          return 0;
  168       }
  169       call->a_args.lock.oh.data = (u8 *) data;
  170    }
  171 
  172    memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
 - 173    return 1;
  174 }
  175 
  176 void
 
- 177 nlmclnt_freegrantargs(struct nlm_rqst *call)
  178 {
  179    struct file_lock *fl = &call->a_args.lock.fl;
  180    /*
  181     * Check whether we allocated memory for the owner.
  182     */
- 183    if (call->a_args.lock.oh.data != (u8 *) call->a_owner) {
  184       kfree(call->a_args.lock.oh.data);
  185    }
- 186    if (fl->fl_ops && fl->fl_ops->fl_release_private)
 - 186   T && T
 - 186   T && F
 - 186   F && _
  187       fl->fl_ops->fl_release_private(fl);
  188 }
  189 
  190 /*
  191  * This is the main entry point for the NLM client.
  192  */
  193 int
 
- 194 nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
  195 {
  196    struct nfs_server   *nfssrv = NFS_SERVER(inode);
  197    struct nlm_host      *host;
  198    struct nlm_rqst      reqst, *call = &reqst;
  199    sigset_t      oldset;
  200    unsigned long      flags;
  201    int         status, proto, vers;
  202 
    203    vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
- 203 ternary-?: ( ( ( ( ( struct nfs_server * ) ( i..
- 204    if (NFS_PROTO(inode)->version > 3) {
  205       printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
 - 206       return -ENOLCK;
  207    }
  208 
  209    /* Retrieve transport protocol from NFS client */
  210    proto = NFS_CLIENT(inode)->cl_xprt->prot;
  211 
- 212    if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
 - 213       return -ENOLCK;
  214 
  215    /* Create RPC client handle if not there, and copy soft
  216     * and intr flags from NFS client. */
- 217    if (host->h_rpcclnt == NULL) {
  218       struct rpc_clnt   *clnt;
  219 
  220       /* Bind an rpc client to this host handle (does not
  221        * perform a portmapper lookup) */
- 222       if (!(clnt = nlm_bind_host(host))) {
  223          status = -ENOLCK;
 - 224          goto done;
  225       }
  226       clnt->cl_softrtry = nfssrv->client->cl_softrtry;
  227       clnt->cl_intr = nfssrv->client->cl_intr;
  228    }
  229 
  230    /* Keep the old signal mask */
    231    spin_lock_irqsave(&current->sighand->siglock, flags);
    231   do
    231     do
- 231     do-while (0)
- 231   do-while (0)
    231   do
    231     do
- 231     do-while (0)
- 231   do-while (0)
- 231 do-while (0)
  232    oldset = current->blocked;
  233 
  234    /* If we're cleaning up locks because the process is exiting,
  235     * perform the RPC call asynchronously. */
  236    if ((IS_SETLK(cmd) || IS_SETLKW(cmd))
  237        && fl->fl_type == F_UNLCK
- 238        && (current->flags & PF_EXITING)) {
 - 238   (((T) || (_)) || ((_) || (_))) && T && (T)
 - 238   (((F) || (T)) || ((_) || (_))) && T && (T)
 - 238   (((F) || (F)) || ((T) || (_))) && T && (T)
 - 238   (((F) || (F)) || ((F) || (T))) && T && (T)
 - 238   (((T) || (_)) || ((_) || (_))) && T && (F)
 - 238   (((T) || (_)) || ((_) || (_))) && F && (_)
 - 238   (((F) || (T)) || ((_) || (_))) && T && (F)
 - 238   (((F) || (T)) || ((_) || (_))) && F && (_)
 - 238   (((F) || (F)) || ((T) || (_))) && T && (F)
 - 238   (((F) || (F)) || ((T) || (_))) && F && (_)
 - 238   (((F) || (F)) || ((F) || (T))) && T && (F)
 - 238   (((F) || (F)) || ((F) || (T))) && F && (_)
 - 238   (((F) || (F)) || ((F) || (F))) && _ && (_)
  239       sigfillset(&current->blocked);   /* Mask all signals */
  240       recalc_sigpending();
    241       spin_unlock_irqrestore(&current->sighand->siglock, flags);
    241     do
    241       do
- 241       do-while (0)
- 241     do-while (0)
- 241   do-while (0)
  242 
  243       call = nlmclnt_alloc_call();
- 244       if (!call) {
  245          status = -ENOMEM;
 - 246          goto out_restore;
  247       }
  248       call->a_flags = RPC_TASK_ASYNC;
    249    } else {
    250       spin_unlock_irqrestore(&current->sighand->siglock, flags);
    250     do
    250       do
- 250       do-while (0)
- 250     do-while (0)
- 250   do-while (0)
  251       memset(call, 0, sizeof(*call));
  252       locks_init_lock(&call->a_args.lock.fl);
  253       locks_init_lock(&call->a_res.lock.fl);
  254    }
  255    call->a_host = host;
  256 
  257    nlmclnt_locks_init_private(fl, host);
  258 
  259    /* Set up the argument struct */
  260    nlmclnt_setlockargs(call, fl);
  261 
- 262    if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
 - 262   ((T) || (_)) || ((_) || (_))
 - 262   ((F) || (T)) || ((_) || (_))
 - 262   ((F) || (F)) || ((T) || (_))
 - 262   ((F) || (F)) || ((F) || (T))
 - 262   ((F) || (F)) || ((F) || (F))
- 263       if (fl->fl_type != F_UNLCK) {
    264          call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
- 264     ternary-?: ( ( 0 ) || ( ( cmd ) == 7 ) )
  265          status = nlmclnt_lock(call, fl);
    266       } else
  267          status = nlmclnt_unlock(call, fl);
- 268    } else if (IS_GETLK(cmd))
 - 268   ((T) || (_))
 - 268   ((F) || (T))
 - 268   ((F) || (F))
  269       status = nlmclnt_test(call, fl);
    270    else
  271       status = -EINVAL;
  272 
  273  out_restore:
    274    spin_lock_irqsave(&current->sighand->siglock, flags);
    274   do
    274     do
- 274     do-while (0)
- 274   do-while (0)
    274   do
    274     do
- 274     do-while (0)
- 274   do-while (0)
- 274 do-while (0)
  275    current->blocked = oldset;
  276    recalc_sigpending();
    277    spin_unlock_irqrestore(&current->sighand->siglock, flags);
    277   do
    277     do
- 277     do-while (0)
- 277   do-while (0)
- 277 do-while (0)
  278 
  279 done:
    280    dprintk("lockd: clnt proc returns %d\n", status);
- 280   if (__builtin_expect ( ! ! ( nlm_debug & 0x0..
- 280 do-while (0)
  281    nlm_release_host(host);
 - 282    return status;
  283 }
  284 EXPORT_SYMBOL(nlmclnt_proc);
  285 
  286 /*
  287  * Allocate an NLM RPC call struct
  288  */
  289 struct nlm_rqst *
 
- 290 nlmclnt_alloc_call(void)
  291 {
  292    struct nlm_rqst   *call;
  293 
- 294    while (!signalled()) {
  295       call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
- 296       if (call) {
  297          memset(call, 0, sizeof(*call));
  298          locks_init_lock(&call->a_args.lock.fl);
  299          locks_init_lock(&call->a_res.lock.fl);
 - 300          return call;
  301       }
  302       printk("nlmclnt_alloc_call: failed, waiting for memory\n");
  303       schedule_timeout_interruptible(5*HZ);
  304    }
 - 305    return NULL;
  306 }
  307 
 
- 308 static int nlm_wait_on_grace(wait_queue_head_t *queue)
  309 {
  310    DEFINE_WAIT(wait);
  311    int status = -EINTR;
  312 
  313    prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
- 314    if (!signalled ()) {
  315       schedule_timeout(NLMCLNT_GRACE_WAIT);
  316       try_to_freeze();
- 317       if (!signalled ())
  318          status = 0;
  319    }
  320    finish_wait(queue, &wait);
 - 321    return status;
  322 }
  323 
  324 /*
  325  * Generic NLM call
  326  */
  327 static int
 
- 328 nlmclnt_call(struct nlm_rqst *req, u32 proc)
  329 {
  330    struct nlm_host   *host = req->a_host;
  331    struct rpc_clnt   *clnt;
  332    struct nlm_args   *argp = &req->a_args;
  333    struct nlm_res   *resp = &req->a_res;
  334    struct rpc_message msg = {
  335       .rpc_argp   = argp,
  336       .rpc_resp   = resp,
  337    };
  338    int      status;
  339 
    340    dprintk("lockd: call procedure %d on %s\n",
- 340   if (__builtin_expect ( ! ! ( nlm_debug & 0x0..
- 340 do-while (0)
  341          (int)proc, host->h_name);
  342 
    343    do {
- 344       if (host->h_reclaiming && !argp->reclaim)
 - 344     T && T
 - 344     T && F
 - 344     F && _
 - 345          goto in_grace_period;
  346 
  347       /* If we have no RPC client yet, create one. */
- 348       if ((clnt = nlm_bind_host(host)) == NULL)
 - 349          return -ENOLCK;
  350       msg.rpc_proc = &clnt->cl_procinfo[proc];
  351 
  352       /* Perform the RPC call. If an error occurs, try again */
- 353       if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
    354          dprintk("lockd: rpc_call returned error %d\n", -status);
- 354       if (__builtin_expect ( ! ! ( nlm_debug &..
- 354     do-while (0)
    355          switch (status) {
 - 356          case -EPROTONOSUPPORT:
  357             status = -EINVAL;
 - 358             break;
 - 359          case -ECONNREFUSED:
 - 360          case -ETIMEDOUT:
 - 361          case -ENOTCONN:
  362             nlm_rebind_host(host);
  363             status = -EAGAIN;
 - 364             break;
 - 365          case -ERESTARTSYS:
    366             return signalled () ? -EINTR : status;
- 366       ternary-?: ( signal_pending ( get_curren..
 - 366       return ( signal_pending ( get_current ( ..
 - 367          default:
 - 368             break;
  369          }
 - 370          break;
  371       } else
- 372       if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
    373          dprintk("lockd: server in grace period\n");
- 373       if (__builtin_expect ( ! ! ( nlm_debug &..
- 373     do-while (0)
- 374          if (argp->reclaim) {
  375             printk(KERN_WARNING
  376                  "lockd: spurious grace period reject?!\n");
 - 377             return -ENOLCK;
  378          }
    379       } else {
- 380          if (!argp->reclaim) {
  381             /* We appear to be out of the grace period */
  382             wake_up_all(&host->h_gracewait);
  383          }
    384          dprintk("lockd: server returns status %d\n", resp->status);
- 384       if (__builtin_expect ( ! ! ( nlm_debug &..
- 384     do-while (0)
 - 385          return 0;   /* Okay, call complete */
  386       }
  387 
  388 in_grace_period:
  389       /*
  390        * The server has rebooted and appears to be in the grace
  391        * period during which locks are only allowed to be
  392        * reclaimed.
  393        * We can only back off and try again later.
  394        */
  395       status = nlm_wait_on_grace(&host->h_gracewait);
- 396    } while (status == 0);
  397 
 - 398    return status;
  399 }
  400