⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dcache.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
 int have_submounts(struct dentry *parent){	struct dentry *this_parent = parent;	struct list_head *next;	spin_lock(&dcache_lock);	if (d_mountpoint(parent))		goto positive;repeat:	next = this_parent->d_subdirs.next;resume:	while (next != &this_parent->d_subdirs) {		struct list_head *tmp = next;		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);		next = tmp->next;		/* Have we found a mount point ? */		if (d_mountpoint(dentry))			goto positive;		if (!list_empty(&dentry->d_subdirs)) {			this_parent = dentry;			goto repeat;		}	}	/*	 * All done at this level ... ascend and resume the search.	 */	if (this_parent != parent) {		next = this_parent->d_child.next; 		this_parent = this_parent->d_parent;		goto resume;	}	spin_unlock(&dcache_lock);	return 0; /* No mount points found in tree */positive:	spin_unlock(&dcache_lock);	return 1;}/* * Search the dentry child list for the specified parent, * and move any unused dentries to the end of the unused * list for prune_dcache(). We descend to the next level * whenever the d_subdirs list is non-empty and continue * searching. */static int select_parent(struct dentry * parent){	struct dentry *this_parent = parent;	struct list_head *next;	int found = 0;	spin_lock(&dcache_lock);repeat:	next = this_parent->d_subdirs.next;resume:	while (next != &this_parent->d_subdirs) {		struct list_head *tmp = next;		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);		next = tmp->next;		if (!atomic_read(&dentry->d_count)) {			list_del(&dentry->d_lru);			list_add(&dentry->d_lru, dentry_unused.prev);			found++;		}		/*		 * Descend a level if the d_subdirs list is non-empty.		 */		if (!list_empty(&dentry->d_subdirs)) {			this_parent = dentry;#ifdef DCACHE_DEBUGprintk(KERN_DEBUG "select_parent: descending to %s/%s, found=%d\n",dentry->d_parent->d_name.name, dentry->d_name.name, found);#endif			goto repeat;		}	}	/*	 * All done at this level ... ascend and resume the search.	 */	if (this_parent != parent) {		next = this_parent->d_child.next; 		this_parent = this_parent->d_parent;#ifdef DCACHE_DEBUGprintk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n",this_parent->d_parent->d_name.name, this_parent->d_name.name, found);#endif		goto resume;	}	spin_unlock(&dcache_lock);	return found;}/** * shrink_dcache_parent - prune dcache * @parent: parent of entries to prune * * Prune the dcache to remove unused children of the parent dentry. */ void shrink_dcache_parent(struct dentry * parent){	int found;	while ((found = select_parent(parent)) != 0)		prune_dcache(found);}/* * This is called from kswapd when we think we need some * more memory, but aren't really sure how much. So we * carefully try to free a _bit_ of our dcache, but not * too much. * * Priority: *   0 - very urgent: shrink everything *  ... *   6 - base-level: try to shrink a bit. */int shrink_dcache_memory(int priority, unsigned int gfp_mask){	int count = 0;	/*	 * Nasty deadlock avoidance.	 *	 * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->	 * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->	 * put_inode->ext2_discard_prealloc->ext2_free_blocks->lock_super->	 * DEADLOCK.	 *	 * We should make sure we don't hold the superblock lock over	 * block allocations, but for now:	 */	if (!(gfp_mask & __GFP_FS))		return 0;	count = dentry_stat.nr_unused / priority;	prune_dcache(count);	kmem_cache_shrink(dentry_cache);	return 0;}#define NAME_ALLOC_LEN(len)	((len+16) & ~15)/** * d_alloc	-	allocate a dcache entry * @parent: parent of entry to allocate * @name: qstr of the name * * Allocates a dentry. It returns %NULL if there is insufficient memory * available. On a success the dentry is returned. The name passed in is * copied and the copy passed in may be reused after this call. */ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name){	char * str;	struct dentry *dentry;	dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); 	if (!dentry)		return NULL;	if (name->len > DNAME_INLINE_LEN-1) {		str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);		if (!str) {			kmem_cache_free(dentry_cache, dentry); 			return NULL;		}	} else		str = dentry->d_iname; 	memcpy(str, name->name, name->len);	str[name->len] = 0;	atomic_set(&dentry->d_count, 1);	dentry->d_vfs_flags = 0;	dentry->d_flags = 0;	dentry->d_inode = NULL;	dentry->d_parent = NULL;	dentry->d_sb = NULL;	dentry->d_name.name = str;	dentry->d_name.len = name->len;	dentry->d_name.hash = name->hash;	dentry->d_op = NULL;	dentry->d_fsdata = NULL;	dentry->d_mounted = 0;	INIT_LIST_HEAD(&dentry->d_hash);	INIT_LIST_HEAD(&dentry->d_lru);	INIT_LIST_HEAD(&dentry->d_subdirs);	INIT_LIST_HEAD(&dentry->d_alias);	if (parent) {		dentry->d_parent = dget(parent);		dentry->d_sb = parent->d_sb;		spin_lock(&dcache_lock);		list_add(&dentry->d_child, &parent->d_subdirs);		spin_unlock(&dcache_lock);	} else		INIT_LIST_HEAD(&dentry->d_child);	dentry_stat.nr_dentry++;	return dentry;}/** * d_instantiate - fill in inode information for a dentry * @entry: dentry to complete * @inode: inode to attach to this dentry * * Fill in inode information in the entry. * * This turns negative dentries into productive full members * of society. * * NOTE! This assumes that the inode count has been incremented * (or otherwise set) by the caller to indicate that it is now * in use by the dcache. */ void d_instantiate(struct dentry *entry, struct inode * inode){	if (!list_empty(&entry->d_alias)) BUG();	spin_lock(&dcache_lock);	if (inode)		list_add(&entry->d_alias, &inode->i_dentry);	entry->d_inode = inode;	spin_unlock(&dcache_lock);}/** * d_alloc_root - allocate root dentry * @root_inode: inode to allocate the root for * * Allocate a root ("/") dentry for the inode given. The inode is * instantiated and returned. %NULL is returned if there is insufficient * memory or the inode passed is %NULL. */ struct dentry * d_alloc_root(struct inode * root_inode){	struct dentry *res = NULL;	if (root_inode) {		res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });		if (res) {			res->d_sb = root_inode->i_sb;			res->d_parent = res;			d_instantiate(res, root_inode);		}	}	return res;}static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash){	hash += (unsigned long) parent / L1_CACHE_BYTES;	hash = hash ^ (hash >> D_HASHBITS);	return dentry_hashtable + (hash & D_HASHMASK);}/** * d_lookup - search for a dentry * @parent: parent dentry * @name: qstr of name we wish to find * * Searches the children of the parent dentry for the name in question. If * the dentry is found its reference count is incremented and the dentry * is returned. The caller must use d_put to free the entry when it has * finished using it. %NULL is returned on failure. */ struct dentry * d_lookup(struct dentry * parent, struct qstr * name){	unsigned int len = name->len;	unsigned int hash = name->hash;	const unsigned char *str = name->name;	struct list_head *head = d_hash(parent,hash);	struct list_head *tmp;	spin_lock(&dcache_lock);	tmp = head->next;	for (;;) {		struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);		if (tmp == head)			break;		tmp = tmp->next;		if (dentry->d_name.hash != hash)			continue;		if (dentry->d_parent != parent)			continue;		if (parent->d_op && parent->d_op->d_compare) {			if (parent->d_op->d_compare(parent, &dentry->d_name, name))				continue;		} else {			if (dentry->d_name.len != len)				continue;			if (memcmp(dentry->d_name.name, str, len))				continue;		}		__dget_locked(dentry);		dentry->d_vfs_flags |= DCACHE_REFERENCED;		spin_unlock(&dcache_lock);		return dentry;	}	spin_unlock(&dcache_lock);	return NULL;}/** * d_validate - verify dentry provided from insecure source * @dentry: The dentry alleged to be valid child of @dparent * @dparent: The parent dentry (known to be valid) * @hash: Hash of the dentry * @len: Length of the name * * An insecure source has sent us a dentry, here we verify it and dget() it. * This is used by ncpfs in its readdir implementation. * Zero is returned in the dentry is invalid. */ int d_validate(struct dentry *dentry, struct dentry *dparent){	unsigned long dent_addr = (unsigned long) dentry;	unsigned long min_addr = PAGE_OFFSET;	unsigned long align_mask = 0x0F;	struct list_head *base, *lhp;	if (dent_addr < min_addr)		goto out;	if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))		goto out;	if (dent_addr & align_mask)		goto out;	if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +						sizeof(struct dentry))))		goto out;	if (dentry->d_parent != dparent)		goto out;	spin_lock(&dcache_lock);	lhp = base = d_hash(dparent, dentry->d_name.hash);	while ((lhp = lhp->next) != base) {		if (dentry == list_entry(lhp, struct dentry, d_hash)) {			__dget_locked(dentry);			spin_unlock(&dcache_lock);			return 1;		}	}	spin_unlock(&dcache_lock);out:	return 0;}/* * When a file is deleted, we have two options: * - turn this dentry into a negative dentry * - unhash this dentry and free it. * * Usually, we want to just turn this into * a negative dentry, but if anybody else is * currently using the dentry or the inode * we can't do that and we fall back on removing * it from the hash queues and waiting for * it to be deleted later when it has no users */ /** * d_delete - delete a dentry * @dentry: The dentry to delete * * Turn the dentry into a negative dentry if possible, otherwise * remove it from the hash queues so it can be deleted later */ void d_delete(struct dentry * dentry){	/*	 * Are we the only user?	 */	spin_lock(&dcache_lock);	if (atomic_read(&dentry->d_count) == 1) {		dentry_iput(dentry);		return;	}	spin_unlock(&dcache_lock);	/*	 * If not, just drop the dentry and let dput	 * pick up the tab..	 */	d_drop(dentry);}/** * d_rehash	- add an entry back to the hash * @entry: dentry to add to the hash * * Adds a dentry to the hash according to its name. */ void d_rehash(struct dentry * entry){	struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);	if (!list_empty(&entry->d_hash)) BUG();	spin_lock(&dcache_lock);	list_add(&entry->d_hash, list);	spin_unlock(&dcache_lock);}#define do_switch(x,y) do { \	__typeof__ (x) __tmp = x; \	x = y; y = __tmp; } while (0)/* * When switching names, the actual string doesn't strictly have to * be preserved in the target - because we're dropping the target * anyway. As such, we can just do a simple memcpy() to copy over * the new name before we switch. * * Note that we have to be a lot more careful about getting the hash * switched - we have to switch the hash value properly even if it * then no longer matches the actual (corrupted) string of the target. * The hash value has to match the hash queue that the dentry is on.. */static inline void switch_names(struct dentry * dentry, struct dentry * target){	const unsigned char *old_name, *new_name;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -