/* * Copyright (c) 1997-2003 Erez Zadok * Copyright (c) 2001-2003 Stony Brook University * * For specific licensing information, see the COPYING file distributed with * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING. * * This Copyright notice must be kept intact and distributed with all * fistgen sources INCLUDING sources generated by fistgen. */ /* * Copyright (C) 2004, 2005 Markus Klotzbuecher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ /* * $Id$ */ #ifdef HAVE_CONFIG_H # include #endif #include "fist.h" #include "mini_fo.h" /* * THIS IS A BOOLEAN FUNCTION: returns 1 if valid, 0 otherwise. */ STATIC int #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) mini_fo_d_revalidate(dentry_t *dentry, struct nameidata *nd) #else mini_fo_d_revalidate(dentry_t *dentry, int flags) #endif { int err1 = 1; /* valid = 1, invalid = 0 */ int err2 = 1; dentry_t *hidden_dentry; dentry_t *hidden_sto_dentry; check_mini_fo_dentry(dentry); hidden_dentry = dtohd(dentry); hidden_sto_dentry = dtohd2(dentry); if(hidden_dentry && hidden_dentry->d_op && hidden_dentry->d_op->d_revalidate) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) err1 = hidden_dentry->d_op->d_revalidate(hidden_dentry, nd); #else err1 = hidden_dentry->d_op->d_revalidate(hidden_dentry, flags); #endif } if(hidden_sto_dentry && hidden_sto_dentry->d_op && hidden_sto_dentry->d_op->d_revalidate) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) err2 = hidden_sto_dentry->d_op->d_revalidate(hidden_sto_dentry, nd); #else err2 = hidden_sto_dentry->d_op->d_revalidate(hidden_sto_dentry, flags); #endif } /* mk: if one of the lower level dentries are valid, * the mini_fo dentry is too. */ return (err1 || err2); } STATIC int mini_fo_d_hash(dentry_t *dentry, qstr_t *name) { int err = 0; dentry_t *hidden_dentry; dentry_t *hidden_sto_dentry; /* hidden_dentry = mini_fo_hidden_dentry(dentry); * hidden_sto_dentry = mini_fo_hidden_sto_dentry(dentry); */ /* state 1, 3, 4, 5: build the hash for the storage dentry */ if((dtopd(dentry)->state == MODIFIED) || (dtopd(dentry)->state == CREATED) || (dtopd(dentry)->state == DEL_REWRITTEN) || (dtopd(dentry)->state == DELETED)) { hidden_sto_dentry = dtohd2(dentry); if(hidden_sto_dentry && hidden_sto_dentry->d_op && hidden_sto_dentry->d_op->d_hash) { err = hidden_sto_dentry->d_op->d_hash(hidden_sto_dentry, name); } goto out; } /* state 2: build the hash for the base dentry */ if(dtopd(dentry)->state == UNMODIFIED) { hidden_dentry = dtohd(dentry); if(hidden_dentry && hidden_dentry->d_op && hidden_dentry->d_op->d_hash) { err = hidden_dentry->d_op->d_hash(hidden_dentry, name); } goto out; } /* state 6: build hash for the dentry that exists */ if(dtopd(dentry)->state == NON_EXISTANT) { hidden_sto_dentry = dtohd2(dentry); if(hidden_sto_dentry && hidden_sto_dentry->d_op && hidden_sto_dentry->d_op->d_hash) { err = hidden_sto_dentry->d_op->d_hash(hidden_sto_dentry, name); goto out; } hidden_dentry = dtohd(dentry); if(hidden_dentry && hidden_dentry->d_op && hidden_dentry->d_op->d_hash) { err = hidden_dentry->d_op->d_hash(hidden_dentry, name); goto out; } } printk(KERN_CRIT "mini_fo: d_hash: invalid state detected.\n"); out: return err; } STATIC int mini_fo_d_compare(dentry_t *dentry, qstr_t *a, qstr_t *b) { int err; dentry_t *hidden_dentry=NULL; /* hidden_dentry = mini_fo_hidden_dentry(dentry); */ if(dtohd2(dentry)) hidden_dentry = dtohd2(dentry); else if(dtohd(dentry)) hidden_dentry = dtohd(dentry); if (hidden_dentry && hidden_dentry->d_op && hidden_dentry->d_op->d_compare) { err = hidden_dentry->d_op->d_compare(hidden_dentry, a, b); } else { err = ((a->len != b->len) || memcmp(a->name, b->name, b->len)); } return err; } int mini_fo_d_delete(dentry_t *dentry) { dentry_t *hidden_dentry; dentry_t *hidden_sto_dentry; int err = 0; /* this could be a negative dentry, so check first */ if (!dtopd(dentry)) { printk(KERN_CRIT "mini_fo_d_delete: negative dentry passed.\n"); goto out; } hidden_dentry = dtohd(dentry); hidden_sto_dentry = dtohd2(dentry); if(hidden_dentry) { if(hidden_dentry->d_op && hidden_dentry->d_op->d_delete) { err = hidden_dentry->d_op->d_delete(hidden_dentry); } } if(hidden_sto_dentry) { if(hidden_sto_dentry->d_op && hidden_sto_dentry->d_op->d_delete) { err = hidden_sto_dentry->d_op->d_delete(hidden_sto_dentry); } } out: return err; } void mini_fo_d_release(dentry_t *dentry) { dentry_t *hidden_dentry; dentry_t *hidden_sto_dentry; /* this could be a negative dentry, so check first */ if (!dtopd(dentry)) { printk(KERN_CRIT "mini_fo_d_release: no private data.\n"); goto out; } hidden_dentry = dtohd(dentry); hidden_sto_dentry = dtohd2(dentry); if(hidden_dentry) { /* decrement hidden dentry's counter and free its inode */ dput(hidden_dentry); } if(hidden_sto_dentry) { /* decrement hidden dentry's counter and free its inode */ dput(hidden_sto_dentry); } /* free private data (mini_fo_dentry_info) here */ kfree(dtopd(dentry)); __dtopd(dentry) = NULL; /* just to be safe */ out: return; } /* * we don't really need mini_fo_d_iput, because dentry_iput will call iput() if * mini_fo_d_iput is not defined. We left this implemented for ease of * tracing/debugging. */ void mini_fo_d_iput(dentry_t *dentry, inode_t *inode) { iput(inode); } struct dentry_operations mini_fo_dops = { d_revalidate: mini_fo_d_revalidate, d_hash: mini_fo_d_hash, d_compare: mini_fo_d_compare, d_release: mini_fo_d_release, d_delete: mini_fo_d_delete, d_iput: mini_fo_d_iput, };