~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/intermezzo/dcache.c

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  2  * vim:expandtab:shiftwidth=8:tabstop=8:
  3  *
  4  *  Original version: Copyright (C) 1996 P. Braam and M. Callahan
  5  *  Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
  6  *  d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
  7  *
  8  *   This file is part of InterMezzo, http://www.inter-mezzo.org.
  9  *
 10  *   InterMezzo is free software; you can redistribute it and/or
 11  *   modify it under the terms of version 2 of the GNU General Public
 12  *   License as published by the Free Software Foundation.
 13  *
 14  *   InterMezzo is distributed in the hope that it will be useful,
 15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17  *   GNU General Public License for more details.
 18  *
 19  *   You should have received a copy of the GNU General Public License
 20  *   along with InterMezzo; if not, write to the Free Software
 21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 22  *
 23  * Directory operations for InterMezzo filesystem
 24  */
 25 
 26 /* inode dentry alias list walking code adapted from linux/fs/dcache.c
 27  *
 28  * fs/dcache.c
 29  *
 30  * (C) 1997 Thomas Schoebel-Theuer,
 31  * with heavy changes by Linus Torvalds
 32  */
 33 
 34 #define __NO_VERSION__
 35 #include <linux/types.h>
 36 #include <linux/kernel.h>
 37 #include <linux/sched.h>
 38 #include <linux/fs.h>
 39 #include <linux/stat.h>
 40 #include <linux/errno.h>
 41 #include <linux/locks.h>
 42 #include <linux/slab.h>
 43 #include <asm/segment.h>
 44 #include <asm/uaccess.h>
 45 #include <linux/string.h>
 46 #include <linux/smp_lock.h>
 47 #include <linux/vmalloc.h>
 48 
 49 #include <linux/intermezzo_fs.h>
 50 
 51 kmem_cache_t * presto_dentry_slab;
 52 
 53 /* called when a cache lookup succeeds */
 54 static int presto_d_revalidate(struct dentry *de, int flag)
 55 {
 56         struct inode *inode = de->d_inode;
 57         struct presto_file_set * root_fset;
 58 
 59         ENTRY;
 60         if (!inode) {
 61                 EXIT;
 62                 return 0;
 63         }
 64 
 65         if (is_bad_inode(inode)) {
 66                 EXIT;
 67                 return 0;
 68         }
 69 
 70         if (!presto_d2d(de)) {
 71                 presto_set_dd(de);
 72         }
 73 
 74         if (!presto_d2d(de)) {
 75                 EXIT;
 76                 return 0;
 77         }
 78 
 79         root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
 80         if (root_fset->fset_flags & FSET_FLAT_BRANCH && 
 81             (presto_d2d(de)->dd_fset != root_fset )) {
 82                 presto_d2d(de)->dd_fset = root_fset;
 83         }
 84 
 85         EXIT;
 86         return 1;
 87 
 88 #if 0
 89         /* The following is needed for metadata on demand. */
 90         if ( S_ISDIR(inode->i_mode) ) {
 91                 EXIT;
 92                 return (presto_chk(de, PRESTO_DATA) &&
 93                         (presto_chk(de, PRESTO_ATTR)));
 94         } else {
 95                 EXIT;
 96                 return presto_chk(de, PRESTO_ATTR);
 97         }
 98 #endif
 99 }
100 
101 static void presto_d_release(struct dentry *dentry)
102 {
103         if (!presto_d2d(dentry)) {
104                 /* This can happen for dentries from NFSd */
105                 return;
106         }
107         presto_d2d(dentry)->dd_count--;
108 
109         if (!presto_d2d(dentry)->dd_count) {
110                 kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
111                 dentry->d_fsdata = NULL;
112         }
113 }
114 
115 struct dentry_operations presto_dentry_ops = 
116 {
117         .d_revalidate =  presto_d_revalidate,
118         .d_release = presto_d_release
119 };
120 
121 static inline int presto_is_dentry_ROOT (struct dentry *dentry)
122 {
123         return(dentry_name_cmp(dentry,"ROOT") &&
124                !dentry_name_cmp(dentry->d_parent,".intermezzo"));
125 }
126 
127 static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
128                 int *is_under_d_intermezzo)
129 {
130         struct dentry* temp_dentry;
131         struct presto_dentry_data *d_data;
132         int found_root=0;
133 
134         ENTRY;
135         CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry, 
136                         dentry->d_name.name);
137 
138         *is_under_d_intermezzo = 0;
139 
140         /* walk up through the branch to get the fileset */
141         /* The dentry we are passed presumably does not have the correct
142          * fset information. However, we still want to start walking up
143          * the branch from this dentry to get our found_root and 
144          * is_under_d_intermezzo decisions correct
145          */
146         for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
147                 CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry, 
148                         temp_dentry->d_name.len,temp_dentry->d_name.name);
149                 if (presto_is_dentry_ROOT(temp_dentry))
150                         found_root = 1;
151                 if (!found_root &&
152                     dentry_name_cmp(temp_dentry, ".intermezzo")) {
153                         *is_under_d_intermezzo = 1;
154                 }
155                 d_data = presto_d2d(temp_dentry);
156                 if (d_data) {
157                         /* If we found a "ROOT" dentry while walking up the
158                          * branch, we will journal regardless of whether
159                          * we are under .intermezzo or not.
160                          * If we are already under d_intermezzo don't reverse
161                          * the decision here...even if we found a "ROOT"
162                          * dentry above .intermezzo (if we were ever to
163                          * modify the directory structure).
164                          */
165                         if (!*is_under_d_intermezzo)  
166                                 *is_under_d_intermezzo = !found_root &&
167                                   (d_data->dd_flags & PRESTO_DONT_JOURNAL);
168                         EXIT;
169                         return d_data->dd_fset;
170                 }
171                 if (temp_dentry->d_parent == temp_dentry) {
172                         break;
173                 }
174         }
175         EXIT;
176         return NULL;
177 }
178 
179 /* Only call this function on positive dentries */
180 static struct presto_dentry_data* presto_try_find_alias_with_dd (
181                   struct dentry* dentry)
182 {
183         struct inode *inode=dentry->d_inode;
184         struct list_head *head, *next, *tmp;
185         struct dentry *tmp_dentry;
186 
187         /* Search through the alias list for dentries with d_fsdata */
188         spin_lock(&dcache_lock);
189         head = &inode->i_dentry;
190         next = inode->i_dentry.next;
191         while (next != head) {
192                 tmp = next;
193                 next = tmp->next;
194                 tmp_dentry = list_entry(tmp, struct dentry, d_alias);
195                 if (!presto_d2d(tmp_dentry)) {
196                         spin_unlock(&dcache_lock);
197                         return presto_d2d(tmp_dentry);
198                 }
199         }
200         spin_unlock(&dcache_lock);
201         return NULL;
202 }
203 
204 /* Only call this function on positive dentries */
205 static void presto_set_alias_dd (struct dentry *dentry, 
206                 struct presto_dentry_data* dd)
207 {
208         struct inode *inode=dentry->d_inode;
209         struct list_head *head, *next, *tmp;
210         struct dentry *tmp_dentry;
211 
212         /* Set d_fsdata for this dentry */
213         dd->dd_count++;
214         dentry->d_fsdata = dd;
215 
216         /* Now set d_fsdata for all dentries in the alias list. */
217         spin_lock(&dcache_lock);
218         head = &inode->i_dentry;
219         next = inode->i_dentry.next;
220         while (next != head) {
221                 tmp = next;
222                 next = tmp->next;
223                 tmp_dentry = list_entry(tmp, struct dentry, d_alias);
224                 if (!presto_d2d(tmp_dentry)) {
225                         dd->dd_count++;
226                         tmp_dentry->d_fsdata = dd;
227                 }
228         }
229         spin_unlock(&dcache_lock);
230         return;
231 }
232 
233 inline struct presto_dentry_data *izo_alloc_ddata(void)
234 {
235         struct presto_dentry_data *dd;
236 
237         dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
238         if (dd == NULL) {
239                 CERROR("IZO: out of memory trying to allocate presto_dentry_data\n");
240                 return NULL;
241         }
242         memset(dd, 0, sizeof(*dd));
243         dd->dd_count = 1;
244 
245         return dd;
246 }
247 
248 /* This uses the BKL! */
249 int presto_set_dd(struct dentry * dentry)
250 {
251         struct presto_file_set *fset = NULL;
252         struct presto_dentry_data *dd;
253         int is_under_d_izo;
254         int error=0;
255 
256         ENTRY;
257 
258         if (!dentry)
259                 BUG();
260 
261         lock_kernel();
262 
263         /* Did we lose a race? */
264         if (dentry->d_fsdata) {
265                 CERROR("dentry %p already has d_fsdata set\n", dentry);
266                 if (dentry->d_inode)
267                         CERROR("    inode: %ld\n", dentry->d_inode->i_ino);
268                 EXIT;
269                 goto out_unlock;
270         }
271 
272         if (dentry->d_inode != NULL) {
273                 /* NFSd runs find_fh_dentry which instantiates disconnected
274                  * dentries which are then connected without a lookup(). 
275                  * So it is possible to have connected dentries that do not 
276                  * have d_fsdata set. So we walk the list trying to find 
277                  * an alias which has its d_fsdata set and then use that 
278                  * for all the other dentries  as well. 
279                  * - SHP,Vinny. 
280                  */
281 
282                 /* If there is an alias with d_fsdata use it. */
283                 if ((dd = presto_try_find_alias_with_dd (dentry))) {
284                         presto_set_alias_dd (dentry, dd);
285                         EXIT;
286                         goto out_unlock;
287                 }
288         } else {
289                 /* Negative dentry */
290                 CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry, 
291                                 dentry->d_name.len, dentry->d_name.name);
292         }
293 
294         /* No pre-existing d_fsdata, we need to construct one.
295          * First, we must walk up the tree to find the fileset 
296          * If a fileset can't be found, we leave a null fsdata
297          * and return EROFS to indicate that we can't journal
298          * updates. 
299          */
300         fset = presto_try_find_fset (dentry, &is_under_d_izo);
301         if (!fset) { 
302 #ifdef PRESTO_NO_NFS
303                 CERROR("No fileset for dentry %p: %*s\n", dentry,
304                                 dentry->d_name.len, dentry->d_name.name);
305 #endif
306                 error = -EROFS;
307                 EXIT;
308                 goto out_unlock;
309         }
310 
311         dentry->d_fsdata = izo_alloc_ddata();
312         if (!presto_d2d(dentry)) {
313                 CERROR ("InterMezzo: out of memory allocating d_fsdata\n");
314                 error = -ENOMEM;
315                 goto out_unlock;
316         }
317         presto_d2d(dentry)->dd_fset = fset;
318         if (is_under_d_izo)
319                 presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
320         EXIT;
321 
322 out_unlock:    
323         CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n", 
324                         dentry, dentry->d_name.len, dentry->d_name.name, 
325                         dentry->d_fsdata);
326         unlock_kernel();
327 
328         if (fset) {
329                 filter_setup_dentry_ops(fset->fset_cache->cache_filter,
330                                         dentry->d_op, &presto_dentry_ops);
331                 dentry->d_op = filter_c2udops(fset->fset_cache->cache_filter);
332         }
333 
334         return error; 
335 }
336 
337 int presto_init_ddata_cache(void)
338 {
339         ENTRY;
340         presto_dentry_slab =
341                 kmem_cache_create("presto_cache",
342                                   sizeof(struct presto_dentry_data), 0,
343                                   SLAB_HWCACHE_ALIGN, NULL,
344                                   NULL);
345         EXIT;
346         return (presto_dentry_slab != NULL);
347 }
348 
349 void presto_cleanup_ddata_cache(void)
350 {
351         kmem_cache_destroy(presto_dentry_slab);
352 }
353 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp