Root/fs/autofs/dirhash.c

1/* -*- linux-c -*- --------------------------------------------------------- *
2 *
3 * linux/fs/autofs/dirhash.c
4 *
5 * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
6 *
7 * This file is part of the Linux kernel and is made available under
8 * the terms of the GNU General Public License, version 2, or at your
9 * option, any later version, incorporated herein by reference.
10 *
11 * ------------------------------------------------------------------------- */
12
13#include "autofs_i.h"
14
15/* Functions for maintenance of expiry queue */
16
17static void autofs_init_usage(struct autofs_dirhash *dh,
18                  struct autofs_dir_ent *ent)
19{
20    list_add_tail(&ent->exp, &dh->expiry_head);
21    ent->last_usage = jiffies;
22}
23
24static void autofs_delete_usage(struct autofs_dir_ent *ent)
25{
26    list_del(&ent->exp);
27}
28
29void autofs_update_usage(struct autofs_dirhash *dh,
30             struct autofs_dir_ent *ent)
31{
32    autofs_delete_usage(ent); /* Unlink from current position */
33    autofs_init_usage(dh,ent); /* Relink at queue tail */
34}
35
36struct autofs_dir_ent *autofs_expire(struct super_block *sb,
37                     struct autofs_sb_info *sbi,
38                     struct vfsmount *mnt)
39{
40    struct autofs_dirhash *dh = &sbi->dirhash;
41    struct autofs_dir_ent *ent;
42    unsigned long timeout = sbi->exp_timeout;
43
44    while (1) {
45        struct path path;
46        int umount_ok;
47
48        if ( list_empty(&dh->expiry_head) || sbi->catatonic )
49            return NULL; /* No entries */
50        /* We keep the list sorted by last_usage and want old stuff */
51        ent = list_entry(dh->expiry_head.next, struct autofs_dir_ent, exp);
52        if (jiffies - ent->last_usage < timeout)
53            break;
54        /* Move to end of list in case expiry isn't desirable */
55        autofs_update_usage(dh, ent);
56
57        /* Check to see that entry is expirable */
58        if ( ent->ino < AUTOFS_FIRST_DIR_INO )
59            return ent; /* Symlinks are always expirable */
60
61        /* Get the dentry for the autofs subdirectory */
62        path.dentry = ent->dentry;
63
64        if (!path.dentry) {
65            /* Should only happen in catatonic mode */
66            printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
67            autofs_delete_usage(ent);
68            continue;
69        }
70
71        if (!path.dentry->d_inode) {
72            dput(path.dentry);
73            printk("autofs: negative dentry on expiry queue: %s\n",
74                   ent->name);
75            autofs_delete_usage(ent);
76            continue;
77        }
78
79        /* Make sure entry is mounted and unused; note that dentry will
80           point to the mounted-on-top root. */
81        if (!S_ISDIR(path.dentry->d_inode->i_mode) ||
82            !d_mountpoint(path.dentry)) {
83            DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
84            continue;
85        }
86        path.mnt = mnt;
87        path_get(&path);
88        if (!follow_down(&path)) {
89            path_put(&path);
90            DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
91            continue;
92        }
93        while (d_mountpoint(path.dentry) && follow_down(&path))
94            ;
95        umount_ok = may_umount(path.mnt);
96        path_put(&path);
97
98        if (umount_ok) {
99            DPRINTK(("autofs: signaling expire on %s\n", ent->name));
100            return ent; /* Expirable! */
101        }
102        DPRINTK(("autofs: didn't expire due to may_umount: %s\n", ent->name));
103    }
104    return NULL; /* No expirable entries */
105}
106
107void autofs_initialize_hash(struct autofs_dirhash *dh) {
108    memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
109    INIT_LIST_HEAD(&dh->expiry_head);
110}
111
112struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name)
113{
114    struct autofs_dir_ent *dhn;
115
116    DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", name->hash));
117    autofs_say(name->name,name->len);
118
119    for ( dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) {
120        if ( name->hash == dhn->hash &&
121             name->len == dhn->len &&
122             !memcmp(name->name, dhn->name, name->len) )
123            break;
124    }
125
126    return dhn;
127}
128
129void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent)
130{
131    struct autofs_dir_ent **dhnp;
132
133    DPRINTK(("autofs_hash_insert: hash = 0x%08x, name = ", ent->hash));
134    autofs_say(ent->name,ent->len);
135
136    autofs_init_usage(dh,ent);
137    if (ent->dentry)
138        dget(ent->dentry);
139
140    dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
141    ent->next = *dhnp;
142    ent->back = dhnp;
143    *dhnp = ent;
144    if ( ent->next )
145        ent->next->back = &(ent->next);
146}
147
148void autofs_hash_delete(struct autofs_dir_ent *ent)
149{
150    *(ent->back) = ent->next;
151    if ( ent->next )
152        ent->next->back = ent->back;
153
154    autofs_delete_usage(ent);
155
156    if ( ent->dentry )
157        dput(ent->dentry);
158    kfree(ent->name);
159    kfree(ent);
160}
161
162/*
163 * Used by readdir(). We must validate "ptr", so we can't simply make it
164 * a pointer. Values below 0xffff are reserved; calling with any value
165 * <= 0x10000 will return the first entry found.
166 *
167 * "last" can be NULL or the value returned by the last search *if* we
168 * want the next sequential entry.
169 */
170struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh,
171                    off_t *ptr, struct autofs_dir_ent *last)
172{
173    int bucket, ecount, i;
174    struct autofs_dir_ent *ent;
175
176    bucket = (*ptr >> 16) - 1;
177    ecount = *ptr & 0xffff;
178
179    if ( bucket < 0 ) {
180        bucket = ecount = 0;
181    }
182
183    DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount));
184
185    ent = last ? last->next : NULL;
186
187    if ( ent ) {
188        ecount++;
189    } else {
190        while ( bucket < AUTOFS_HASH_SIZE ) {
191            ent = dh->h[bucket];
192            for ( i = ecount ; ent && i ; i-- )
193                ent = ent->next;
194            
195            if (ent) {
196                ecount++; /* Point to *next* entry */
197                break;
198            }
199            
200            bucket++; ecount = 0;
201        }
202    }
203
204#ifdef DEBUG
205    if ( !ent )
206        printk("autofs_hash_enum: nothing found\n");
207    else {
208        printk("autofs_hash_enum: found hash %08x, name", ent->hash);
209        autofs_say(ent->name,ent->len);
210    }
211#endif
212
213    *ptr = ((bucket+1) << 16) + ecount;
214    return ent;
215}
216
217/* Iterate over all the ents, and remove all dentry pointers. Used on
218   entering catatonic mode, in order to make the filesystem unmountable. */
219void autofs_hash_dputall(struct autofs_dirhash *dh)
220{
221    int i;
222    struct autofs_dir_ent *ent;
223
224    for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
225        for ( ent = dh->h[i] ; ent ; ent = ent->next ) {
226            if ( ent->dentry ) {
227                dput(ent->dentry);
228                ent->dentry = NULL;
229            }
230        }
231    }
232}
233
234/* Delete everything. This is used on filesystem destruction, so we
235   make no attempt to keep the pointers valid */
236void autofs_hash_nuke(struct autofs_sb_info *sbi)
237{
238    int i;
239    struct autofs_dir_ent *ent, *nent;
240
241    for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
242        for ( ent = sbi->dirhash.h[i] ; ent ; ent = nent ) {
243            nent = ent->next;
244            if ( ent->dentry )
245                dput(ent->dentry);
246            kfree(ent->name);
247            kfree(ent);
248        }
249    }
250}
251

Archive Download this file



interactive