Rev 3 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /* |
2 | * Project: HARTIK (HA-rd R-eal TI-me K-ernel) |
||
3 | * |
||
4 | * Coordinators: Giorgio Buttazzo <giorgio@sssup.it> |
||
5 | * Gerardo Lamastra <gerardo@sssup.it> |
||
6 | * |
||
7 | * Authors : Massimiliano Giorgi <massy@hartik.sssup.it> |
||
8 | * (see authors.txt for full list of hartik's authors) |
||
9 | * |
||
10 | * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy) |
||
11 | * |
||
12 | * http://www.sssup.it |
||
13 | * http://retis.sssup.it |
||
14 | * http://hartik.sssup.it |
||
15 | */ |
||
16 | |||
17 | /* |
||
18 | * Copyright (C) 1999 Massimiliano Giorgi |
||
19 | * |
||
20 | * This program is free software; you can redistribute it and/or modify |
||
21 | * it under the terms of the GNU General Public License as published by |
||
22 | * the Free Software Foundation; either version 2 of the License, or |
||
23 | * (at your option) any later version. |
||
24 | * |
||
25 | * This program is distributed in the hope that it will be useful, |
||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
28 | * GNU General Public License for more details. |
||
29 | * |
||
30 | * You should have received a copy of the GNU General Public License |
||
31 | * along with this program; if not, write to the Free Software |
||
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
33 | * |
||
34 | */ |
||
35 | |||
36 | /* |
||
37 | * CVS : $Id: dentry.c,v 1.1.1.1 2002-03-29 14:12:50 pj Exp $ |
||
38 | * |
||
39 | * File: $File$ |
||
40 | * Revision: $Revision: 1.1.1.1 $ |
||
41 | * Last update: $Date: 2002-03-29 14:12:50 $ |
||
42 | */ |
||
43 | |||
44 | #include <fs/util.h> |
||
45 | #include <fs/types.h> |
||
46 | #include <fs/assert.h> |
||
47 | #include "fs.h" |
||
48 | #include "super.h" |
||
49 | #include "superop.h" |
||
50 | #include "dentry.h" |
||
51 | #include "dentryop.h" |
||
52 | #include "inode.h" |
||
53 | #include "inodeop.h" |
||
54 | #include "fsconst.h" |
||
55 | #include "mutex.h" |
||
56 | |||
57 | #include "debug.h" |
||
58 | |||
59 | /* |
||
60 | * DEBUG |
||
61 | */ |
||
62 | |||
63 | /* if defined: |
||
64 | * a short message is printed on console when a task go in/out of |
||
65 | * functions dentry_find() & dentry_unlock() |
||
66 | * (after and before the lock/unlock of the mutex!) |
||
67 | */ |
||
68 | #define DEBUGFINDUNLOCK KERN_DEBUG |
||
69 | #undef DEBUGFINDUNLOCK |
||
70 | |||
71 | #ifdef DEBUGFINDUNLOCK |
||
72 | #define printdd(fmt,pid) kern_printf(fmt,pid) |
||
73 | #else |
||
74 | #define printdd(fmt,pid) |
||
75 | #endif |
||
76 | |||
77 | /* if you modify this you must modify MAXINODE */ |
||
78 | #define MAXDENTRY 128 |
||
79 | |||
80 | static __fs_mutex_t mutex; |
||
81 | static __fs_fastmutex_t mutexreq; |
||
82 | static struct dentry *freelist; |
||
83 | //static struct dentry *leaflist; |
||
84 | static struct dentry direntry[MAXDENTRY]; |
||
85 | |||
86 | static struct dentry *root_direntry=NULL; |
||
87 | |||
88 | #ifdef FSMUTEXCHECK |
||
89 | void debug_dump_dentry_mutex(void) |
||
90 | { |
||
91 | //printk(KERN_DEBUG "dentry mutex: %i",(int)mutex); |
||
92 | //printk(KERN_DEBUG "dentry mutex req: %i",(int)mutexreq); |
||
93 | } |
||
94 | |||
95 | //static __fs_mutex_t regmutex; |
||
96 | //static __fs_mutex_t regmutexreq; |
||
97 | |||
98 | int debug_check_dentry_mutex(void) |
||
99 | { |
||
100 | /* |
||
101 | if (mutex!=regmutex) { |
||
102 | printk(KERN_DEBUG "dentry mutex CHANGED! (prev: %i)",regmutex); |
||
103 | return 0; |
||
104 | } |
||
105 | if (mutexreq!=regmutexreq) { |
||
106 | printk(KERN_DEBUG "dentry mutexreq CHANGED! (prev: %i)",regmutexreq); |
||
107 | return 0; |
||
108 | } |
||
109 | */ |
||
110 | return -1; |
||
111 | } |
||
112 | |||
113 | void debug_save_dentry_mutex(void) |
||
114 | { |
||
115 | //regmutex=mutex; |
||
116 | //regmutexreq=mutexreq; |
||
117 | } |
||
118 | #endif |
||
119 | |||
120 | int dentry_init(void) |
||
121 | { |
||
122 | int i; |
||
123 | |||
124 | __fs_mutex_init(&mutex); |
||
125 | __fs_fastmutex_init(&mutexreq); |
||
126 | |||
127 | #ifdef FSMUTEXCHECK |
||
128 | debug_save_dentry_mutex(); |
||
129 | #endif |
||
130 | |||
131 | freelist=direntry; |
||
132 | for (i=0;i<MAXDENTRY;i++) { |
||
133 | memset(direntry+i,0,sizeof(struct dentry)); |
||
134 | magic_set(direntry[i].magic,DENTRY_MAGIC); |
||
135 | direntry[i].d_next=direntry+i+1; |
||
136 | direntry[i].d_lock=-1; |
||
137 | } |
||
138 | direntry[MAXDENTRY-1].d_next=NULL; |
||
139 | return 0; |
||
140 | } |
||
141 | |||
142 | static __inline__ struct dentry *__get_dentry(void) |
||
143 | { |
||
144 | struct dentry *den; |
||
145 | if (freelist==NULL) return NULL; |
||
146 | den=freelist; |
||
147 | freelist=den->d_next; |
||
148 | |||
149 | _assert(den->d_lock==-1); |
||
150 | magic_assert(den->magic,DENTRY_MAGIC,"get_dentry: dentry MAGIC failed!"); |
||
151 | |||
152 | den->d_lock=0; |
||
153 | return den; |
||
154 | } |
||
155 | |||
156 | /* get a dentry from the free queue */ |
||
157 | struct dentry *get_dentry(void) |
||
158 | { |
||
159 | struct dentry *den; |
||
160 | __fs_fastmutex_lock(&mutexreq); |
||
161 | den=__get_dentry(); |
||
162 | __fs_fastmutex_unlock(&mutexreq); |
||
163 | return den; |
||
164 | } |
||
165 | |||
166 | static __inline__ void __free_dentry(struct dentry *den) |
||
167 | { |
||
168 | _assert(den>=direntry&&den<direntry+MAXDENTRY); |
||
169 | _assert(den->d_lock==0); |
||
170 | magic_assert(den->magic,DENTRY_MAGIC,"free_dentry: dentry MAGIC failed!"); |
||
171 | |||
172 | den->d_lock=-1; |
||
173 | den->d_next=freelist; |
||
174 | freelist=den; |
||
175 | } |
||
176 | |||
177 | /* insert dentry into the free queue */ |
||
178 | void free_dentry(struct dentry *den) |
||
179 | { |
||
180 | __fs_fastmutex_lock(&mutexreq); |
||
181 | __free_dentry(den); |
||
182 | __fs_fastmutex_unlock(&mutexreq); |
||
183 | } |
||
184 | |||
185 | static void __insert_dentry(struct dentry *den, struct dentry *parent) |
||
186 | { |
||
187 | _assert(den>=direntry&&den<direntry+MAXDENTRY); |
||
188 | magic_assert(den->magic,DENTRY_MAGIC,"insert_dentry: dentry MAGIC failed!"); |
||
189 | |||
190 | den->d_acc=gettimek(); |
||
191 | den->d_parent=parent; |
||
192 | den->d_child=NULL; |
||
193 | den->d_prev=NULL; |
||
194 | den->d_next=parent->d_child; |
||
195 | if (parent->d_child!=NULL) |
||
196 | parent->d_child->d_prev=den; |
||
197 | parent->d_child=den; |
||
198 | } |
||
199 | |||
200 | /* insert a dentry into the tree */ |
||
201 | void insert_dentry(struct dentry *den, struct dentry *parent) |
||
202 | { |
||
203 | __fs_mutex_lock(&mutex); |
||
204 | __insert_dentry(den,parent); |
||
205 | __fs_mutex_unlock(&mutex); |
||
206 | } |
||
207 | |||
208 | static void __remove_dentry_only(struct dentry *den) |
||
209 | { |
||
210 | _assert(den>=direntry&&den<direntry+MAXDENTRY); |
||
211 | magic_assert(den->magic,DENTRY_MAGIC,"remove_dentry: dentry MAGIC failed!"); |
||
212 | _assert(den->d_lock==0); |
||
213 | |||
214 | if (den->d_prev!=NULL) |
||
215 | den->d_prev->d_next=den->d_next; |
||
216 | else |
||
217 | den->d_parent->d_child=den->d_next; |
||
218 | if (den->d_next!=NULL) |
||
219 | den->d_next->d_prev=den->d_prev; |
||
220 | } |
||
221 | |||
222 | static __inline__ void __remove_dentry(struct dentry *den) |
||
223 | { |
||
224 | __remove_dentry_only(den); |
||
225 | unlock_inode(den->d_inode); |
||
226 | } |
||
227 | |||
228 | /* remove a dentry from the tree */ |
||
229 | void remove_dentry(struct dentry *den) |
||
230 | { |
||
231 | __fs_mutex_lock(&mutex); |
||
232 | __remove_dentry(den); |
||
233 | __fs_mutex_unlock(&mutex); |
||
234 | } |
||
235 | |||
236 | /* find the oldest dentry into the tree */ |
||
237 | /* |
||
238 | * (potrebbe essere fatto in maniera non ricorsiva usando un |
||
239 | * puntatore alle foglie e scandendo questa lista invece di visitare |
||
240 | * tutto l'albero!) |
||
241 | * |
||
242 | * si potrebbe usare un task NRT periodico per mantenere liberi (se |
||
243 | * possibile l'X% delle dentry libere. |
||
244 | */ |
||
245 | |||
246 | static struct dentry *__recurse(struct dentry *den, struct dentry *act) |
||
247 | { |
||
248 | while (den!=NULL) { |
||
249 | if (den->d_child!=NULL) { |
||
250 | act=__recurse(den->d_child,act); |
||
251 | } else { |
||
252 | if (den->d_lock==0) { |
||
253 | if (act==NULL) |
||
254 | act=den; |
||
255 | else { |
||
256 | if (den->d_acc<act->d_acc) |
||
257 | act=den; |
||
258 | } |
||
259 | } |
||
260 | } |
||
261 | den=den->d_next; |
||
262 | } |
||
263 | return act; |
||
264 | } |
||
265 | |||
266 | struct dentry *__purge_dentry(void) |
||
267 | { |
||
268 | struct dentry *act; |
||
269 | act=__recurse(root_direntry,NULL); |
||
270 | if (act!=NULL) __remove_dentry(act); |
||
271 | return act; |
||
272 | } |
||
273 | |||
274 | /* find & remove the oldest dentry from the tree */ |
||
275 | struct dentry *purge_dentry(void) |
||
276 | { |
||
277 | struct dentry *act; |
||
278 | __fs_mutex_lock(&mutex); |
||
279 | act=__purge_dentry(); |
||
280 | __fs_mutex_unlock(&mutex); |
||
281 | return act; |
||
282 | } |
||
283 | |||
284 | struct dentry *__catch_dentry(void) |
||
285 | { |
||
286 | struct dentry *den; |
||
287 | den=__get_dentry(); |
||
288 | if (den==NULL) den=__purge_dentry(); |
||
289 | return den; |
||
290 | } |
||
291 | |||
292 | /* get a dentry by searching into the free space or purging an old one */ |
||
293 | /* |
||
294 | static struct dentry *catch_dentry(void) |
||
295 | { |
||
296 | struct dentry *den; |
||
297 | __fs_mutex_lock(&mutex); |
||
298 | den=__catch_dentry(); |
||
299 | __fs_mutex_unlock(&mutex); |
||
300 | return den; |
||
301 | } |
||
302 | */ |
||
303 | |||
304 | /*---------------------*/ |
||
305 | |||
306 | int set_root_dentry(struct super_block *sb) |
||
307 | { |
||
308 | struct dentry *den; |
||
309 | |||
310 | __fs_mutex_lock(&mutex); |
||
311 | if (sb==NULL) { |
||
312 | _assert(root_direntry!=NULL); |
||
313 | root_direntry->d_lock--; |
||
314 | _assert(root_direntry->d_lock==1); |
||
315 | root_direntry=NULL; |
||
316 | __fs_mutex_unlock(&mutex); |
||
317 | return 0; |
||
318 | } |
||
319 | _assert(root_direntry==NULL); |
||
320 | __fs_mutex_unlock(&mutex); |
||
321 | |||
322 | den=get_dentry(); |
||
323 | if (den==NULL) return -1; |
||
324 | |||
325 | den->d_next=NULL; |
||
326 | den->d_prev=NULL; |
||
327 | den->d_parent=NULL; |
||
328 | den->d_child=NULL; |
||
329 | |||
330 | den->d_acc=0; |
||
331 | den->d_name.nameptr=ROOTDIRNAME; |
||
332 | |||
333 | den->d_op=sb->sb_dop; |
||
334 | den->d_sb=sb; |
||
335 | den->d_inode=sb->sb_root; |
||
336 | |||
337 | den->d_lock=1; |
||
338 | |||
339 | sb->sb_droot=den; |
||
340 | root_direntry=den; |
||
341 | |||
342 | return 0; |
||
343 | } |
||
344 | |||
345 | struct dentry *get_root_dentry(void) |
||
346 | { |
||
347 | _assert(root_direntry!=NULL); |
||
348 | return root_direntry; |
||
349 | } |
||
350 | |||
351 | #ifdef DEBUG_FIND_DUMP |
||
352 | static void dump_dentry(struct dentry *ptr) |
||
353 | { |
||
354 | printk7(KERN_DEBUG "dentry dump:"); |
||
355 | printk7(KERN_DEBUG " name : %s",QSTRNAME(&ptr->d_name)); |
||
356 | printk7(KERN_DEBUG " lock : %i",ptr->d_lock); |
||
357 | printk7(KERN_DEBUG " inode: %i",ptr->d_inode->i_st.st_ino); |
||
358 | } |
||
359 | #else |
||
360 | #define dump_dentry(x) |
||
361 | #endif |
||
362 | |||
363 | /*--------------*/ |
||
364 | |||
365 | /* |
||
366 | * flags for createflags: |
||
367 | * DENTRY_NOCREATE -> can't create a new inode |
||
368 | * DENTRY_CANCREATE -> an inode (only the last) can be created |
||
369 | * DENTRY_MUSTCREATE -> the last inode MUST be created (it must no exist) |
||
370 | * |
||
371 | * return flags for createflags: |
||
372 | * DENTRY_CREATED -> the last inode has been created |
||
373 | * DENTRY_EXIST -> (error) the last inode already exist |
||
374 | * |
||
375 | * return NULL on error (not found or DENTRY_EXIST) |
||
376 | * |
||
377 | * NB: |
||
378 | * if createflag is NULL a DENTRY_NOCREATE is assumed |
||
379 | * 'act' can be NULL if pathname is an absolute path |
||
380 | */ |
||
381 | |||
382 | struct dentry *find_dentry_from_ext(struct dentry *act, |
||
383 | char *pathname, |
||
384 | int *createflag) |
||
385 | { |
||
386 | struct dentry *ptr; |
||
387 | struct dentry *den; |
||
388 | struct inode *ino; |
||
389 | struct qstr str; |
||
390 | char *sp; |
||
391 | char *s; |
||
392 | int found,created; |
||
393 | |||
394 | /* too much 'goto' :-( and 'if' */ |
||
395 | |||
396 | sp=pathname; |
||
397 | if (*pathname==DIRDELIMCHAR) { |
||
398 | act=root_direntry; |
||
399 | sp++; |
||
400 | } |
||
401 | if (act==NULL) return NULL; |
||
402 | |||
403 | printdd("°f<%i>",exec_shadow); |
||
404 | __fs_mutex_lock(&mutex); |
||
405 | printdd("±f<%i>",exec_shadow); |
||
406 | |||
407 | if (*sp=='\0') goto END0; |
||
408 | |||
409 | created=0; |
||
410 | found=1; |
||
411 | while (found) { |
||
412 | s=strchr(sp,DIRDELIMCHAR); |
||
413 | if (s!=NULL) *s='\0'; |
||
414 | |||
415 | printk7("dentry find: searching for %s...",sp); |
||
416 | |||
417 | /* for handle special directory entry "." and ".." */ |
||
418 | if (*sp=='.') { |
||
419 | if (*sp=='\0') { |
||
420 | /* found "." special directory */ |
||
421 | printk7("dentry find: special directory entry '.'"); |
||
422 | found=1; |
||
423 | if (s==NULL) goto END0; |
||
424 | *s=DIRDELIMCHAR; |
||
425 | sp=s+1; |
||
426 | s=strchr(sp,DIRDELIMCHAR); |
||
427 | continue; |
||
428 | } |
||
429 | if (*sp=='.') { |
||
430 | if (*sp=='\0') { |
||
431 | /* found ".." special directory */ |
||
432 | printk7("dentry find: special directory entry '..'"); |
||
433 | found=1; |
||
434 | if (act->d_parent!=NULL) act=act->d_parent; |
||
435 | if (s==NULL) goto END0; |
||
436 | *s=DIRDELIMCHAR; |
||
437 | sp=s+1; |
||
438 | s=strchr(sp,DIRDELIMCHAR); |
||
439 | continue; |
||
440 | } |
||
441 | } |
||
442 | } |
||
443 | |||
444 | ptr=act->d_child; |
||
445 | found=0; |
||
446 | str.nameptr=sp; |
||
447 | while (ptr!=NULL) { |
||
448 | if (ptr->d_op->d_compare(ptr,&ptr->d_name,&str)==0) { |
||
449 | |||
450 | printk7("dentry find: found!"); |
||
451 | |||
452 | found=1; |
||
453 | act=ptr; |
||
454 | if (s==NULL) goto END0; |
||
455 | *s=DIRDELIMCHAR; |
||
456 | sp=s+1; |
||
457 | s=strchr(sp,DIRDELIMCHAR); |
||
458 | break; |
||
459 | } |
||
460 | ptr=ptr->d_next; |
||
461 | } |
||
462 | } |
||
463 | |||
464 | printk7("dentry find: NOT found!"); |
||
465 | |||
466 | for (;;) { |
||
467 | den=__catch_dentry(); |
||
468 | if (den==NULL) { |
||
469 | if (s!=NULL) *s=DIRDELIMCHAR; |
||
470 | printk7("dentry find: can't have new struct dentry!"); |
||
471 | act=NULL; |
||
472 | goto END1; |
||
473 | } |
||
474 | |||
475 | den->d_acc=0; |
||
476 | den->d_name.nameptr=NULL; |
||
477 | strcpy(den->d_name.name,sp); |
||
478 | den->d_lock=0; |
||
479 | den->d_op=act->d_op; |
||
480 | den->d_sb=act->d_sb; |
||
481 | |||
482 | printk7("dentry find: looking up for %s....",sp); |
||
483 | dump_dentry(act); |
||
484 | |||
485 | ino=act->d_inode->i_op->lookup(act->d_inode,den); |
||
486 | |||
487 | printk7("dentry find: end looking"); |
||
488 | |||
489 | if (ino==NULL) { |
||
490 | |||
491 | printk7("dentry find: NOT found!"); |
||
492 | if (s!=NULL) *s=DIRDELIMCHAR; |
||
493 | |||
494 | if (createflag==NULL) { |
||
495 | __free_dentry(den); |
||
496 | act=NULL; |
||
497 | goto END1; |
||
498 | } |
||
499 | |||
500 | if ((s==NULL)&&(*createflag&DENTRY_CANCREATE)) { |
||
501 | |||
502 | printk7("dentry find: check for read-only fs"); |
||
503 | if (!(act->d_sb->sb_mopts.flags&MOUNT_FLAG_RW)) { |
||
504 | printk7("dentry find: read-only fs.. creating new inode fails"); |
||
505 | __free_dentry(den); |
||
506 | act=NULL; |
||
507 | goto END1; |
||
508 | } |
||
509 | |||
510 | printk7("dentry find: try to create a new inode"); |
||
511 | ino=act->d_inode->i_op->create(act->d_inode,den); |
||
512 | |||
513 | if (ino==NULL) { |
||
514 | printk7("dentry find: inode creation fail"); |
||
515 | __free_dentry(den); |
||
516 | act=NULL; |
||
517 | goto END1; |
||
518 | } |
||
519 | printk7("dentry find: new inode created"); |
||
520 | created=1; |
||
521 | |||
522 | } else { |
||
523 | __free_dentry(den); |
||
524 | act=NULL; |
||
525 | goto END1; |
||
526 | } |
||
527 | } |
||
528 | den->d_inode=ino; |
||
529 | |||
530 | insert_inode(ino); |
||
531 | printk7("dentry find: found!"); |
||
532 | |||
533 | __insert_dentry(den,act); |
||
534 | act=den; |
||
535 | |||
536 | if (s==NULL) goto END2; |
||
537 | |||
538 | sp=s+1; |
||
539 | *s=DIRDELIMCHAR; |
||
540 | s=strchr(sp,DIRDELIMCHAR); |
||
541 | if (s!=NULL) *s='\0'; |
||
542 | } |
||
543 | |||
544 | /* for safety */ |
||
545 | _assert(0==-1); |
||
546 | |||
547 | END0: |
||
548 | /* 'if found' we are here */ |
||
549 | if (createflag!=NULL) { |
||
550 | *createflag&=~DENTRY_CREATEMASK; |
||
551 | if (*createflag&DENTRY_MUSTCREATE) { |
||
552 | _assert(act!=NULL); |
||
553 | *createflag|=DENTRY_EXIST; |
||
554 | act=NULL; |
||
555 | } |
||
556 | } |
||
557 | goto END; |
||
558 | |||
559 | END1: |
||
560 | /* 'if error' we are here */ |
||
561 | _assert(act==NULL); |
||
562 | if (createflag!=NULL) *createflag&=~DENTRY_CREATEMASK; |
||
563 | goto END; |
||
564 | |||
565 | END2: |
||
566 | /* 'if ok' (found or created) we are here */ |
||
567 | _assert(act!=NULL); |
||
568 | if (createflag!=NULL) { |
||
569 | if (created) { |
||
570 | *createflag&=~DENTRY_CREATEMASK; |
||
571 | *createflag|=DENTRY_CREATED; |
||
572 | } else if ((*createflag&DENTRY_MUSTCREATE)==DENTRY_MUSTCREATE) { |
||
573 | *createflag&=~DENTRY_CREATEMASK; |
||
574 | *createflag|=DENTRY_EXIST; |
||
575 | act=NULL; |
||
576 | } else |
||
577 | *createflag&=~DENTRY_CREATEMASK; |
||
578 | } |
||
579 | goto END; |
||
580 | |||
581 | END: |
||
582 | if (act!=NULL) act->d_lock++; |
||
583 | |||
584 | printdd("²f<%i>",exec_shadow); |
||
585 | __fs_mutex_unlock(&mutex); |
||
586 | printdd("Ûf<%i>",exec_shadow); |
||
587 | return act; |
||
588 | |||
589 | } |
||
590 | |||
591 | void unlock_dentry(struct dentry *den) |
||
592 | { |
||
593 | printdd("°u<%i>",exec_shadow); |
||
594 | __fs_mutex_lock(&mutex); |
||
595 | printdd("±u<%i>",exec_shadow); |
||
596 | |||
597 | _assert(den>=direntry&&den<direntry+MAXDENTRY); |
||
598 | if (den->d_lock<=0) { |
||
599 | printk(KERN_DEBUG "unlock_dentry on %s",QSTRNAME(&den->d_name)); |
||
600 | } |
||
601 | _assert(den->d_lock>0); |
||
602 | |||
603 | den->d_lock--; |
||
604 | //if (den->d_lock==0) { |
||
605 | // _assert(den->d_inode!=NULL); |
||
606 | // unlock_inode(den->d_inode); |
||
607 | //} |
||
608 | |||
609 | printdd("²u<%i>",exec_shadow); |
||
610 | __fs_mutex_unlock(&mutex); |
||
611 | printdd("Ûu<%i>",exec_shadow); |
||
612 | } |
||
613 | |||
614 | /* |
||
615 | * |
||
616 | */ |
||
617 | |||
618 | static void __print_name(struct dentry *act,char *buffer) |
||
619 | { |
||
620 | if (act->d_parent==NULL) return; |
||
621 | __print_name(act->d_parent,buffer); |
||
622 | strcat(buffer,ROOTDIRNAME); |
||
623 | strcat(buffer,QSTRNAME(&act->d_name)); |
||
624 | return; |
||
625 | } |
||
626 | |||
627 | static char *print_name(struct dentry *act) |
||
628 | { |
||
629 | static char buffer[1024]; |
||
630 | buffer[0]='\0'; |
||
631 | __print_name(act,buffer); |
||
632 | return buffer; |
||
633 | } |
||
634 | |||
635 | void getfullname_dentry(struct dentry *act, char *buffer, int size) |
||
636 | { |
||
637 | _assert(act>=direntry&&act<direntry+MAXDENTRY); |
||
638 | magic_assert(act->magic,DENTRY_MAGIC, |
||
639 | "getfullname_dentry: dentry MAGIC failed!"); |
||
640 | |||
641 | buffer[0]='\0'; |
||
642 | __print_name(act,buffer); |
||
643 | _assert(strlen(buffer)<size); |
||
644 | } |
||
645 | |||
646 | static void visit_tree(struct dentry *act) |
||
647 | { |
||
648 | struct dentry *ptr; |
||
649 | if (act==root_direntry) printk(KERN_DEBUG " %s",ROOTDIRNAME); |
||
650 | else { char *s=print_name(act); printk(KERN_DEBUG " %s",s);} |
||
651 | ptr=act->d_child; |
||
652 | while (ptr!=NULL) { |
||
653 | visit_tree(ptr); |
||
654 | ptr=ptr->d_next; |
||
655 | } |
||
656 | return; |
||
657 | } |
||
658 | |||
659 | void dump_dentry_tree(void) |
||
660 | { |
||
661 | printk(KERN_DEBUG "DTREE dump"); |
||
662 | visit_tree(root_direntry); |
||
663 | } |
||
664 | |||
665 | /* |
||
666 | * |
||
667 | */ |
||
668 | |||
669 | #ifdef DEBUGPURGECHILD |
||
670 | #define dprint(fmt,args...) printk(fmt,##args) |
||
671 | #else |
||
672 | #define dprint(fmt,args...) |
||
673 | #endif |
||
674 | |||
675 | static __inline__ int __purgeallchilds_mg(struct dentry *de) |
||
676 | { |
||
677 | int ret; |
||
678 | struct dentry *ptr,*ptr2,*ptr3; |
||
679 | |||
680 | dprint(KERN_DEBUG "START mg purgechild"); |
||
681 | |||
682 | { |
||
683 | #ifdef DEBUGPURGECHILD |
||
684 | char *s=print_name(de); |
||
685 | dprint(KERN_DEBUG "for %s",s); |
||
686 | #endif |
||
687 | } |
||
688 | |||
689 | /* |
||
690 | * Phase 1 |
||
691 | * purge all childs (if possible!) |
||
692 | */ |
||
693 | |||
694 | ptr=de->d_child; |
||
695 | ret=0; |
||
696 | |||
697 | /* why these? I do not want to use recursion... (or goto statement)*/ |
||
698 | for (;;) { |
||
699 | /* if there is a child... continue using the child's chain */ |
||
700 | if (ptr->d_child!=NULL) { |
||
701 | ptr=ptr->d_child; |
||
702 | continue; |
||
703 | } |
||
704 | /* if a child dentry is locked... can't continue! */ |
||
705 | if (ptr->d_lock) { |
||
706 | #ifdef DEBUGPURGECHILD |
||
707 | char *s=print_name(ptr); |
||
708 | dprint(KERN_DEBUG "%s is locked!!!",s); |
||
709 | #endif |
||
710 | ret=-1; |
||
711 | break; |
||
712 | } |
||
713 | /* purge this dentry */ |
||
714 | ptr2=ptr->d_next; |
||
715 | ptr3=ptr->d_parent; |
||
716 | |||
717 | dprint(KERN_DEBUG "%s destroy",QSTRNAME(&ptr->d_name)); |
||
718 | ret=destroy_inode(ptr->d_inode); |
||
719 | if (ret) break; |
||
720 | __remove_dentry_only(ptr); |
||
721 | |||
722 | /* if there is not another child... continue with the parent */ |
||
723 | if (ptr2==NULL) { |
||
724 | ptr=ptr3; |
||
725 | if (ptr==de) break; |
||
726 | continue; |
||
727 | } |
||
728 | /* continue with next child */ |
||
729 | ptr=ptr2; |
||
730 | } |
||
731 | |||
732 | dprint(KERN_DEBUG "END mg purgechild"); |
||
733 | return ret; |
||
734 | } |
||
735 | |||
736 | static __inline__ int __purgeallchilds_pj(struct dentry *x) |
||
737 | { |
||
738 | struct dentry *p,*q; |
||
739 | |||
740 | dprint(KERN_DEBUG "START pj purgechild"); |
||
741 | |||
742 | p = x->d_child; |
||
743 | q = NULL; |
||
744 | for(;;) { |
||
745 | /* scorro i figli */ |
||
746 | while(p) { |
||
747 | q = p; |
||
748 | p = p->d_next; |
||
749 | } |
||
750 | |||
751 | if (q == x) { |
||
752 | dprint(KERN_DEBUG "END pj purgechild"); |
||
753 | return 0; /* finito */ |
||
754 | } |
||
755 | |||
756 | if (q->d_child) { |
||
757 | p = q->d_child; |
||
758 | q = NULL; |
||
759 | } |
||
760 | else { |
||
761 | /* sono su un nodo senza figli */ |
||
762 | /* q punta al nodo */ |
||
763 | if (q->d_prev) |
||
764 | { /* non e' il primo figlio */ |
||
765 | q = q->d_prev; |
||
766 | if (q->d_next->d_lock) { |
||
767 | dprint(KERN_DEBUG "%s is locked", |
||
768 | QSTRNAME(&q->d_next->d_name)); |
||
769 | return -1; |
||
770 | } |
||
771 | if (destroy_inode(q->d_next->d_inode)) { |
||
772 | dprint(KERN_DEBUG "error destroing %s", |
||
773 | QSTRNAME(&q->d_next->d_name)); |
||
774 | return -1; |
||
775 | } |
||
776 | dprint(KERN_DEBUG "removing %s",QSTRNAME(&q->d_next->d_name)); |
||
777 | __remove_dentry_only(q->d_next); |
||
778 | q->d_next = NULL; |
||
779 | p = NULL; |
||
780 | } |
||
781 | else { |
||
782 | /* e' il primo figlio */ |
||
783 | q = q->d_parent; |
||
784 | if (q->d_child->d_lock) { |
||
785 | dprint(KERN_DEBUG "%s is locked", |
||
786 | QSTRNAME(&q->d_child->d_name)); |
||
787 | return -1; |
||
788 | } |
||
789 | if (destroy_inode(q->d_child->d_inode)) { |
||
790 | dprint(KERN_DEBUG "error destroing %s", |
||
791 | QSTRNAME(&q->d_child->d_name)); |
||
792 | return -1; |
||
793 | } |
||
794 | dprint(KERN_DEBUG "removing %s",QSTRNAME(&q->d_child->d_name)); |
||
795 | __remove_dentry_only(q->d_child); |
||
796 | q->d_child = NULL; |
||
797 | p = NULL; |
||
798 | } |
||
799 | } |
||
800 | } |
||
801 | |||
802 | } |
||
803 | |||
804 | #define __purgeallchilds(de) __purgeallchilds_mg(de) |
||
805 | |||
806 | int mount_dentry(struct super_block *sb, struct dentry *de) |
||
807 | { |
||
808 | int ret; |
||
809 | |||
810 | printk9("START mount_dentry()!"); |
||
811 | printk9("for %s",QSTRNAME(&de->d_name)); |
||
812 | |||
813 | _assert(de!=NULL); |
||
814 | _assert(sb!=NULL); |
||
815 | |||
816 | __fs_mutex_lock(&mutex); |
||
817 | |||
818 | printk9("locked and ready"); |
||
819 | |||
820 | if (de->d_lock>1) { |
||
821 | printk9("LOCKED!"); |
||
822 | /* someone is using this dentry! */ |
||
823 | __fs_mutex_unlock(&mutex); |
||
824 | return -1; |
||
825 | } |
||
826 | |||
827 | /* |
||
828 | * Phase 1 |
||
829 | */ |
||
830 | |||
831 | /* purge all childs (if possible) */ |
||
832 | |||
833 | if (de->d_child!=NULL) { |
||
834 | ret=__purgeallchilds(de); |
||
835 | if (ret) { |
||
836 | printk9("PURGECHILD!"); |
||
837 | __fs_mutex_unlock(&mutex); |
||
838 | return ret; |
||
839 | } |
||
840 | |||
841 | } |
||
842 | |||
843 | /* |
||
844 | * Phase 2 |
||
845 | */ |
||
846 | |||
847 | ret=destroy_inode(de->d_inode); |
||
848 | if (ret) { |
||
849 | printk9("DESTROY INODE!"); |
||
850 | __fs_mutex_unlock(&mutex); |
||
851 | return ret; |
||
852 | } |
||
853 | |||
854 | de->d_op=sb->sb_dop; |
||
855 | de->d_inode=sb->sb_root; |
||
856 | de->d_sb=sb; |
||
857 | |||
858 | sb->sb_droot=de; |
||
859 | |||
860 | __fs_mutex_unlock(&mutex); |
||
861 | printk9("END mount_dentry()!"); |
||
862 | return 0; |
||
863 | } |
||
864 | |||
865 | int umount_dentry(struct super_block *sb) |
||
866 | { |
||
867 | struct dentry *de; |
||
868 | int res; |
||
869 | |||
870 | printk9("START umount_dentry()"); |
||
871 | |||
872 | __fs_mutex_lock(&mutex); |
||
873 | |||
874 | _assert(sb!=NULL); |
||
875 | _assert(sb->sb_droot!=NULL); |
||
876 | if (sb->sb_droot->d_child!=NULL) { |
||
877 | res=__purgeallchilds(sb->sb_droot); |
||
878 | if (res) { |
||
879 | printk9("PURGING CHILD!"); |
||
880 | __fs_mutex_unlock(&mutex); |
||
881 | return res; |
||
882 | } |
||
883 | } |
||
884 | |||
885 | printk9("umount_dentry: phase 1"); |
||
886 | |||
887 | de=sb->sb_droot; |
||
888 | _assert(de->d_lock>0); |
||
889 | if (de->d_lock!=1) { |
||
890 | printk9("LOCK COUNT! (%i)",de->d_lock); |
||
891 | __fs_mutex_unlock(&mutex); |
||
892 | return -1; |
||
893 | } |
||
894 | de->d_lock--; |
||
895 | |||
896 | printk9("umount_dentry: phase 2"); |
||
897 | |||
898 | __remove_dentry_only(de); |
||
899 | destroy_inode(de->d_inode); |
||
900 | __free_dentry(de); |
||
901 | |||
902 | printk9("umount_dentry: phase 3"); |
||
903 | |||
904 | sb->sb_droot=NULL; |
||
905 | sb->sb_root=NULL; |
||
906 | |||
907 | __fs_mutex_unlock(&mutex); |
||
908 | |||
909 | printk9("END umount_dentry()!"); |
||
910 | return 0; |
||
911 | } |
||
912 | |||
913 | int unlink_dentry(struct dentry *d) |
||
914 | { |
||
915 | struct inode *in; |
||
916 | int res; |
||
917 | |||
918 | printkd("unlink_dentry: START"); |
||
919 | |||
920 | __fs_mutex_lock(&mutex); |
||
921 | if (d->d_lock!=1) return EBUSY; |
||
922 | |||
923 | in=d->d_inode; |
||
924 | |||
925 | printkd("unlink_dentry: dentry ok"); |
||
926 | |||
927 | __rwlock_wrlock(&in->i_lock); |
||
928 | |||
929 | printkd("unlink_dentry: locked inode"); |
||
930 | |||
931 | res=in->i_op->unlink(d); |
||
932 | |||
933 | printkd("unlink_dentry: inode unlinked from dentry"); |
||
934 | |||
935 | if (res==0&&in->i_st.st_nlink==0) { |
||
936 | printkd("unlink_dentry: no more links erasing inode"); |
||
937 | erase_inode(in); |
||
938 | } |
||
939 | |||
940 | __rwlock_wrunlock(&in->i_lock); |
||
941 | |||
942 | printkd("unlink_dentry: unlocked inode"); |
||
943 | |||
944 | if (res==0) { |
||
945 | d->d_lock--; |
||
946 | __remove_dentry_only(d); |
||
947 | printkd("unlink_dentry: dentry unlinked"); |
||
948 | } |
||
949 | |||
950 | __fs_mutex_unlock(&mutex); |
||
951 | |||
952 | printkd("unlink_dentry: END"); |
||
953 | return -res; |
||
954 | } |