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

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


File: fs/autofs4/expire.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/213)

Start/ End/    
True False - Line Source

  1 /* -*- c -*- --------------------------------------------------------------- *
  2  *
  3  * linux/fs/autofs/expire.c
  4  *
  5  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  6  *  Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
  7  *  Copyright 2001-2003 Ian Kent <raven@themaw.net>
  8  *
  9  * This file is part of the Linux kernel and is made available under
  10  * the terms of the GNU General Public License, version 2, or at your
  11  * option, any later version, incorporated herein by reference.
  12  *
  13  * ------------------------------------------------------------------------- */
  14 
  15 #include "autofs_i.h"
  16 
  17 static unsigned long now;
  18 
  19 /* Check if a dentry can be expired return 1 if it can else return 0 */
 
- 20 static inline int autofs4_can_expire(struct dentry *dentry,
  21                unsigned long timeout, int do_now)
  22 {
  23    struct autofs_info *ino = autofs4_dentry_ino(dentry);
  24 
  25    /* dentry in the process of being deleted */
- 26    if (ino == NULL)
 - 27       return 0;
  28 
  29    /* No point expiring a pending mount */
- 30    if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
 - 31       return 0;
  32 
- 33    if (!do_now) {
  34       /* Too young to die */
- 35       if (time_after(ino->last_used + timeout, now))
 - 35     ((T) && (T) && (T))
 - 35     ((T) && (T) && (F))
 - 35     ((T) && (F) && (_))
 - 35     ((F) && (_) && (_))
 - 36          return 0;
  37 
  38       /* update last_used here :-
  39          - obviously makes sense if it is in use now
  40          - less obviously, prevents rapid-fire expire
  41            attempts if expire fails the first time */
  42       ino->last_used = now;
  43    }
  44 
 - 45    return 1;
  46 }
  47 
  48 /* Check a mount point for busyness return 1 if not busy, otherwise */
 
- 49 static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry)
  50 {
  51    int status = 0;
  52 
    53    DPRINTK("dentry %p %.*s",
- 53 do-while (0)
  54       dentry, (int)dentry->d_name.len, dentry->d_name.name);
  55 
  56    mntget(mnt);
  57    dget(dentry);
  58 
- 59    if (!autofs4_follow_mount(&mnt, &dentry))
 - 60       goto done;
  61 
  62    /* This is an autofs submount, we can't expire it */
- 63    if (is_autofs4_dentry(dentry))
 - 64       goto done;
  65 
  66    /* The big question */
- 67    if (may_umount_tree(mnt) == 0)
  68       status = 1;
  69 done:
    70    DPRINTK("returning = %d", status);
- 70 do-while (0)
  71    mntput(mnt);
  72    dput(dentry);
 - 73    return status;
  74 }
  75 
  76 /* Check a directory tree of mount points for busyness
  77  * The tree is not busy iff no mountpoints are busy
  78  * Return 1 if the tree is busy or 0 otherwise
  79  */
 
- 80 static int autofs4_check_tree(struct vfsmount *mnt,
  81                       struct dentry *top,
  82                unsigned long timeout,
  83                int do_now)
  84 {
  85    struct dentry *this_parent = top;
  86    struct list_head *next;
  87 
    88    DPRINTK("parent %p %.*s",
- 88 do-while (0)
  89       top, (int)top->d_name.len, top->d_name.name);
  90 
  91    /* Negative dentry - give up */
- 92    if (!simple_positive(top))
 - 93       return 0;
  94 
  95    /* Timeout of a tree mount is determined by its top dentry */
- 96    if (!autofs4_can_expire(top, timeout, do_now))
 - 97       return 0;
  98 
  99    /* Is someone visiting anywhere in the tree ? */
- 100    if (may_umount_tree(mnt))
 - 101       return 0;
  102 
    103    spin_lock(&dcache_lock);
    103   do
- 103   do-while (0)
- 103 do-while (0)
  104 repeat:
  105    next = this_parent->d_subdirs.next;
  106 resume:
- 107    while (next != &this_parent->d_subdirs) {
  108       struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
  109 
  110       /* Negative dentry - give up */
- 111       if (!simple_positive(dentry)) {
  112          next = next->next;
 - 113          continue;
  114       }
  115 
    116       DPRINTK("dentry %p %.*s",
- 116   do-while (0)
  117          dentry, (int)dentry->d_name.len, dentry->d_name.name);
  118 
- 119       if (!simple_empty_nolock(dentry)) {
  120          this_parent = dentry;
 - 121          goto repeat;
  122       }
  123 
  124       dentry = dget(dentry);
    125       spin_unlock(&dcache_lock);
    125     do
- 125     do-while (0)
- 125   do-while (0)
  126 
- 127       if (d_mountpoint(dentry)) {
  128          /* First busy => tree busy */
- 129          if (!autofs4_check_mount(mnt, dentry)) {
  130             dput(dentry);
 - 131             return 0;
  132          }
  133       }
  134 
  135       dput(dentry);
    136       spin_lock(&dcache_lock);
    136     do
- 136     do-while (0)
- 136   do-while (0)
  137       next = next->next;
  138    }
  139 
- 140    if (this_parent != top) {
  141       next = this_parent->d_u.d_child.next;
  142       this_parent = this_parent->d_parent;
 - 143       goto resume;
  144    }
    145    spin_unlock(&dcache_lock);
    145   do
- 145   do-while (0)
- 145 do-while (0)
  146 
 - 147    return 1;
  148 }
  149 
 
- 150 static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
  151                   struct dentry *parent,
  152                   unsigned long timeout,
  153                   int do_now)
  154 {
  155    struct dentry *this_parent = parent;
  156    struct list_head *next;
  157 
    158    DPRINTK("parent %p %.*s",
- 158 do-while (0)
  159       parent, (int)parent->d_name.len, parent->d_name.name);
  160 
    161    spin_lock(&dcache_lock);
    161   do
- 161   do-while (0)
- 161 do-while (0)
  162 repeat:
  163    next = this_parent->d_subdirs.next;
  164 resume:
- 165    while (next != &this_parent->d_subdirs) {
  166       struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
  167 
  168       /* Negative dentry - give up */
- 169       if (!simple_positive(dentry)) {
  170          next = next->next;
 - 171          continue;
  172       }
  173 
    174       DPRINTK("dentry %p %.*s",
- 174   do-while (0)
  175          dentry, (int)dentry->d_name.len, dentry->d_name.name);
  176 
- 177       if (!list_empty(&dentry->d_subdirs)) {
  178          this_parent = dentry;
 - 179          goto repeat;
  180       }
  181 
  182       dentry = dget(dentry);
    183       spin_unlock(&dcache_lock);
    183     do
- 183     do-while (0)
- 183   do-while (0)
  184 
- 185       if (d_mountpoint(dentry)) {
  186          /* Can we expire this guy */
- 187          if (!autofs4_can_expire(dentry, timeout, do_now))
 - 188             goto cont;
  189 
  190          /* Can we umount this guy */
- 191          if (autofs4_check_mount(mnt, dentry))
 - 192             return dentry;
  193 
  194       }
  195 cont:
  196       dput(dentry);
    197       spin_lock(&dcache_lock);
    197     do
- 197     do-while (0)
- 197   do-while (0)
  198       next = next->next;
  199    }
  200 
- 201    if (this_parent != parent) {
  202       next = this_parent->d_u.d_child.next;
  203       this_parent = this_parent->d_parent;
 - 204       goto resume;
  205    }
    206    spin_unlock(&dcache_lock);
    206   do
- 206   do-while (0)
- 206 do-while (0)
  207 
 - 208    return NULL;
  209 }
  210 
  211 /*
  212  * Find an eligible tree to time-out
  213  * A tree is eligible if :-
  214  *  - it is unused by any user process
  215  *  - it has been unused for exp_timeout time
  216  */
 
- 217 static struct dentry *autofs4_expire(struct super_block *sb,
  218                  struct vfsmount *mnt,
  219                  struct autofs_sb_info *sbi,
  220                  int how)
  221 {
  222    unsigned long timeout;
  223    struct dentry *root = sb->s_root;
  224    struct dentry *expired = NULL;
  225    struct list_head *next;
  226    int do_now = how & AUTOFS_EXP_IMMEDIATE;
  227    int exp_leaves = how & AUTOFS_EXP_LEAVES;
  228 
- 229    if ( !sbi->exp_timeout || !root )
 - 229   T || _
 - 229   F || T
 - 229   F || F
 - 230       return NULL;
  231 
  232    now = jiffies;
  233    timeout = sbi->exp_timeout;
  234 
    235    spin_lock(&dcache_lock);
    235   do
- 235   do-while (0)
- 235 do-while (0)
  236    next = root->d_subdirs.next;
  237 
  238    /* On exit from the loop expire is set to a dgot dentry
  239     * to expire or it's NULL */
- 240    while ( next != &root->d_subdirs ) {
  241       struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
  242 
  243       /* Negative dentry - give up */
- 244       if ( !simple_positive(dentry) ) {
  245          next = next->next;
 - 246          continue;
  247       }
  248 
  249       dentry = dget(dentry);
    250       spin_unlock(&dcache_lock);
    250     do
- 250     do-while (0)
- 250   do-while (0)
  251 
  252       /* Case 1: indirect mount or top level direct mount */
- 253       if (d_mountpoint(dentry)) {
    254          DPRINTK("checking mountpoint %p %.*s",
- 254     do-while (0)
  255             dentry, (int)dentry->d_name.len, dentry->d_name.name);
  256 
  257          /* Can we expire this guy */
- 258          if (!autofs4_can_expire(dentry, timeout, do_now))
 - 259             goto next;
  260 
  261          /* Can we umount this guy */
- 262          if (autofs4_check_mount(mnt, dentry)) {
  263             expired = dentry;
 - 264             break;
  265          }
 - 266          goto next;
  267       }
  268 
- 269       if ( simple_empty(dentry) )
 - 270          goto next;
  271 
  272       /* Case 2: tree mount, expire iff entire tree is not busy */
- 273       if (!exp_leaves) {
  274          /* Lock the tree as we must expire as a whole */
    275          spin_lock(&sbi->fs_lock);
    275       do
- 275       do-while (0)
- 275     do-while (0)
- 276          if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
  277             struct autofs_info *inf = autofs4_dentry_ino(dentry);
  278 
  279             /* Set this flag early to catch sys_chdir and the like */
  280             inf->flags |= AUTOFS_INF_EXPIRING;
    281             spin_unlock(&sbi->fs_lock);
    281         do
- 281         do-while (0)
- 281       do-while (0)
  282             expired = dentry;
 - 283             break;
  284          }
    285          spin_unlock(&sbi->fs_lock);
    285       do
- 285       do-while (0)
- 285     do-while (0)
  286       /* Case 3: direct mount, expire individual leaves */
    287       } else {
  288          expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
- 289          if (expired) {
  290             dput(dentry);
 - 291             break;
  292          }
  293       }
  294 next:
  295       dput(dentry);
    296       spin_lock(&dcache_lock);
    296     do
- 296     do-while (0)
- 296   do-while (0)
  297       next = next->next;
  298    }
  299 
- 300    if ( expired ) {
    301       DPRINTK("returning %p %.*s",
- 301   do-while (0)
  302          expired, (int)expired->d_name.len, expired->d_name.name);
    303       spin_lock(&dcache_lock);
    303     do
- 303     do-while (0)
- 303   do-while (0)
  304       list_del(&expired->d_parent->d_subdirs);
  305       list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
    306       spin_unlock(&dcache_lock);
    306     do
- 306     do-while (0)
- 306   do-while (0)
 - 307       return expired;
  308    }
    309    spin_unlock(&dcache_lock);
    309   do
- 309   do-while (0)
- 309 do-while (0)
  310 
 - 311    return NULL;
  312 }
  313 
  314 /* Perform an expiry operation */
 
- 315 int autofs4_expire_run(struct super_block *sb,
  316             struct vfsmount *mnt,
  317             struct autofs_sb_info *sbi,
  318             struct autofs_packet_expire __user *pkt_p)
  319 {
  320    struct autofs_packet_expire pkt;
  321    struct dentry *dentry;
  322 
  323    memset(&pkt,0,sizeof pkt);
  324 
  325    pkt.hdr.proto_version = sbi->version;
  326    pkt.hdr.type = autofs_ptype_expire;
  327 
- 328    if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
 - 329       return -EAGAIN;
  330 
  331    pkt.len = dentry->d_name.len;
  332    memcpy(pkt.name, dentry->d_name.name, pkt.len);
  333    pkt.name[pkt.len] = '\0';
  334    dput(dentry);
  335 
- 336    if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
 - 337       return -EFAULT;
  338 
 - 339    return 0;
  340 }
  341 
  342 /* Call repeatedly until it returns -EAGAIN, meaning there's nothing
  343    more to be done */
 
- 344 int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
  345          struct autofs_sb_info *sbi, int __user *arg)
  346 {
  347    struct dentry *dentry;
  348    int ret = -EAGAIN;
  349    int do_now = 0;
  350 
- 351    if (arg && get_user(do_now, arg))
 - 351   T && (T)
 - 351   T && (F)
 - 351   F && (_)
 - 352       return -EFAULT;
  353 
- 354    if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
  355       struct autofs_info *de_info = autofs4_dentry_ino(dentry);
  356 
  357       /* This is synchronous because it makes the daemon a
  358                    little easier */
  359       de_info->flags |= AUTOFS_INF_EXPIRING;
  360       ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
  361       de_info->flags &= ~AUTOFS_INF_EXPIRING;
  362       dput(dentry);
  363    }
  364       
 - 365    return ret;
  366 }
  367 
***TER 0% (0/213) of SOURCE FILE expire.c

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