Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platf...
[pandora-kernel.git] / drivers / staging / autofs / dirhash.c
1 /* -*- linux-c -*- --------------------------------------------------------- *
2  *
3  * drivers/staging/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
17 static 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
24 static void autofs_delete_usage(struct autofs_dir_ent *ent)
25 {
26         list_del(&ent->exp);
27 }
28
29 void 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
36 struct 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
107 void 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
112 struct 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
129 void 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
148 void 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  */
170 struct 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. */
219 void 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 */
236 void 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 }