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

📄 xattr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (EXT3_I(inode)->i_state & EXT3_STATE_XATTR) {		error = ext3_xattr_check_names(IFIRST(header), is->s.end);		if (error)			return error;		/* Find the named attribute. */		error = ext3_xattr_find_entry(&is->s.here, i->name_index,					      i->name, is->s.end -					      (void *)is->s.base, 0);		if (error && error != -ENODATA)			return error;		is->s.not_found = error;	}	return 0;}static intext3_xattr_ibody_set(handle_t *handle, struct inode *inode,		     struct ext3_xattr_info *i,		     struct ext3_xattr_ibody_find *is){	struct ext3_xattr_ibody_header *header;	struct ext3_xattr_search *s = &is->s;	int error;	if (EXT3_I(inode)->i_extra_isize == 0)		return -ENOSPC;	error = ext3_xattr_set_entry(i, s);	if (error)		return error;	header = IHDR(inode, ext3_raw_inode(&is->iloc));	if (!IS_LAST_ENTRY(s->first)) {		header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC);		EXT3_I(inode)->i_state |= EXT3_STATE_XATTR;	} else {		header->h_magic = cpu_to_le32(0);		EXT3_I(inode)->i_state &= ~EXT3_STATE_XATTR;	}	return 0;}/* * ext3_xattr_set_handle() * * Create, replace or remove an extended attribute for this inode. Buffer * is NULL to remove an existing extended attribute, and non-NULL to * either replace an existing extended attribute, or create a new extended * attribute. The flags XATTR_REPLACE and XATTR_CREATE * specify that an extended attribute must exist and must not exist * previous to the call, respectively. * * Returns 0, or a negative error number on failure. */intext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,		      const char *name, const void *value, size_t value_len,		      int flags){	struct ext3_xattr_info i = {		.name_index = name_index,		.name = name,		.value = value,		.value_len = value_len,	};	struct ext3_xattr_ibody_find is = {		.s = { .not_found = -ENODATA, },	};	struct ext3_xattr_block_find bs = {		.s = { .not_found = -ENODATA, },	};	int error;	if (!name)		return -EINVAL;	if (strlen(name) > 255)		return -ERANGE;	down_write(&EXT3_I(inode)->xattr_sem);	error = ext3_get_inode_loc(inode, &is.iloc);	if (error)		goto cleanup;	if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {		struct ext3_inode *raw_inode = ext3_raw_inode(&is.iloc);		memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size);		EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW;	}	error = ext3_xattr_ibody_find(inode, &i, &is);	if (error)		goto cleanup;	if (is.s.not_found)		error = ext3_xattr_block_find(inode, &i, &bs);	if (error)		goto cleanup;	if (is.s.not_found && bs.s.not_found) {		error = -ENODATA;		if (flags & XATTR_REPLACE)			goto cleanup;		error = 0;		if (!value)			goto cleanup;	} else {		error = -EEXIST;		if (flags & XATTR_CREATE)			goto cleanup;	}	error = ext3_journal_get_write_access(handle, is.iloc.bh);	if (error)		goto cleanup;	if (!value) {		if (!is.s.not_found)			error = ext3_xattr_ibody_set(handle, inode, &i, &is);		else if (!bs.s.not_found)			error = ext3_xattr_block_set(handle, inode, &i, &bs);	} else {		error = ext3_xattr_ibody_set(handle, inode, &i, &is);		if (!error && !bs.s.not_found) {			i.value = NULL;			error = ext3_xattr_block_set(handle, inode, &i, &bs);		} else if (error == -ENOSPC) {			error = ext3_xattr_block_set(handle, inode, &i, &bs);			if (error)				goto cleanup;			if (!is.s.not_found) {				i.value = NULL;				error = ext3_xattr_ibody_set(handle, inode, &i,							     &is);			}		}	}	if (!error) {		ext3_xattr_update_super_block(handle, inode->i_sb);		inode->i_ctime = CURRENT_TIME_SEC;		error = ext3_mark_iloc_dirty(handle, inode, &is.iloc);		/*		 * The bh is consumed by ext3_mark_iloc_dirty, even with		 * error != 0.		 */		is.iloc.bh = NULL;		if (IS_SYNC(inode))			handle->h_sync = 1;	}cleanup:	brelse(is.iloc.bh);	brelse(bs.bh);	up_write(&EXT3_I(inode)->xattr_sem);	return error;}/* * ext3_xattr_set() * * Like ext3_xattr_set_handle, but start from an inode. This extended * attribute modification is a filesystem transaction by itself. * * Returns 0, or a negative error number on failure. */intext3_xattr_set(struct inode *inode, int name_index, const char *name,	       const void *value, size_t value_len, int flags){	handle_t *handle;	int error, retries = 0;retry:	handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));	if (IS_ERR(handle)) {		error = PTR_ERR(handle);	} else {		int error2;		error = ext3_xattr_set_handle(handle, inode, name_index, name,					      value, value_len, flags);		error2 = ext3_journal_stop(handle);		if (error == -ENOSPC &&		    ext3_should_retry_alloc(inode->i_sb, &retries))			goto retry;		if (error == 0)			error = error2;	}	return error;}/* * ext3_xattr_delete_inode() * * Free extended attribute resources associated with this inode. This * is called immediately before an inode is freed. We have exclusive * access to the inode. */voidext3_xattr_delete_inode(handle_t *handle, struct inode *inode){	struct buffer_head *bh = NULL;	if (!EXT3_I(inode)->i_file_acl)		goto cleanup;	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);	if (!bh) {		ext3_error(inode->i_sb, __FUNCTION__,			"inode %lu: block "E3FSBLK" read error", inode->i_ino,			EXT3_I(inode)->i_file_acl);		goto cleanup;	}	if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||	    BHDR(bh)->h_blocks != cpu_to_le32(1)) {		ext3_error(inode->i_sb, __FUNCTION__,			"inode %lu: bad block "E3FSBLK, inode->i_ino,			EXT3_I(inode)->i_file_acl);		goto cleanup;	}	ext3_xattr_release_block(handle, inode, bh);	EXT3_I(inode)->i_file_acl = 0;cleanup:	brelse(bh);}/* * ext3_xattr_put_super() * * This is called when a file system is unmounted. */voidext3_xattr_put_super(struct super_block *sb){	mb_cache_shrink(sb->s_bdev);}/* * ext3_xattr_cache_insert() * * Create a new entry in the extended attribute cache, and insert * it unless such an entry is already in the cache. * * Returns 0, or a negative error number on failure. */static voidext3_xattr_cache_insert(struct buffer_head *bh){	__u32 hash = le32_to_cpu(BHDR(bh)->h_hash);	struct mb_cache_entry *ce;	int error;	ce = mb_cache_entry_alloc(ext3_xattr_cache);	if (!ce) {		ea_bdebug(bh, "out of memory");		return;	}	error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);	if (error) {		mb_cache_entry_free(ce);		if (error == -EBUSY) {			ea_bdebug(bh, "already in cache");			error = 0;		}	} else {		ea_bdebug(bh, "inserting [%x]", (int)hash);		mb_cache_entry_release(ce);	}}/* * ext3_xattr_cmp() * * Compare two extended attribute blocks for equality. * * Returns 0 if the blocks are equal, 1 if they differ, and * a negative error number on errors. */static intext3_xattr_cmp(struct ext3_xattr_header *header1,	       struct ext3_xattr_header *header2){	struct ext3_xattr_entry *entry1, *entry2;	entry1 = ENTRY(header1+1);	entry2 = ENTRY(header2+1);	while (!IS_LAST_ENTRY(entry1)) {		if (IS_LAST_ENTRY(entry2))			return 1;		if (entry1->e_hash != entry2->e_hash ||		    entry1->e_name_index != entry2->e_name_index ||		    entry1->e_name_len != entry2->e_name_len ||		    entry1->e_value_size != entry2->e_value_size ||		    memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))			return 1;		if (entry1->e_value_block != 0 || entry2->e_value_block != 0)			return -EIO;		if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),			   (char *)header2 + le16_to_cpu(entry2->e_value_offs),			   le32_to_cpu(entry1->e_value_size)))			return 1;		entry1 = EXT3_XATTR_NEXT(entry1);		entry2 = EXT3_XATTR_NEXT(entry2);	}	if (!IS_LAST_ENTRY(entry2))		return 1;	return 0;}/* * ext3_xattr_cache_find() * * Find an identical extended attribute block. * * Returns a pointer to the block found, or NULL if such a block was * not found or an error occurred. */static struct buffer_head *ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header,		      struct mb_cache_entry **pce){	__u32 hash = le32_to_cpu(header->h_hash);	struct mb_cache_entry *ce;	if (!header->h_hash)		return NULL;  /* never share */	ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);again:	ce = mb_cache_entry_find_first(ext3_xattr_cache, 0,				       inode->i_sb->s_bdev, hash);	while (ce) {		struct buffer_head *bh;		if (IS_ERR(ce)) {			if (PTR_ERR(ce) == -EAGAIN)				goto again;			break;		}		bh = sb_bread(inode->i_sb, ce->e_block);		if (!bh) {			ext3_error(inode->i_sb, __FUNCTION__,				"inode %lu: block %lu read error",				inode->i_ino, (unsigned long) ce->e_block);		} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=				EXT3_XATTR_REFCOUNT_MAX) {			ea_idebug(inode, "block %lu refcount %d>=%d",				  (unsigned long) ce->e_block,				  le32_to_cpu(BHDR(bh)->h_refcount),					  EXT3_XATTR_REFCOUNT_MAX);		} else if (ext3_xattr_cmp(header, BHDR(bh)) == 0) {			*pce = ce;			return bh;		}		brelse(bh);		ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);	}	return NULL;}#define NAME_HASH_SHIFT 5#define VALUE_HASH_SHIFT 16/* * ext3_xattr_hash_entry() * * Compute the hash of an extended attribute. */static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header,					 struct ext3_xattr_entry *entry){	__u32 hash = 0;	char *name = entry->e_name;	int n;	for (n=0; n < entry->e_name_len; n++) {		hash = (hash << NAME_HASH_SHIFT) ^		       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^		       *name++;	}	if (entry->e_value_block == 0 && entry->e_value_size != 0) {		__le32 *value = (__le32 *)((char *)header +			le16_to_cpu(entry->e_value_offs));		for (n = (le32_to_cpu(entry->e_value_size) +		     EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) {			hash = (hash << VALUE_HASH_SHIFT) ^			       (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^			       le32_to_cpu(*value++);		}	}	entry->e_hash = cpu_to_le32(hash);}#undef NAME_HASH_SHIFT#undef VALUE_HASH_SHIFT#define BLOCK_HASH_SHIFT 16/* * ext3_xattr_rehash() * * Re-compute the extended attribute hash value after an entry has changed. */static void ext3_xattr_rehash(struct ext3_xattr_header *header,			      struct ext3_xattr_entry *entry){	struct ext3_xattr_entry *here;	__u32 hash = 0;	ext3_xattr_hash_entry(header, entry);	here = ENTRY(header+1);	while (!IS_LAST_ENTRY(here)) {		if (!here->e_hash) {			/* Block is not shared if an entry's hash value == 0 */			hash = 0;			break;		}		hash = (hash << BLOCK_HASH_SHIFT) ^		       (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^		       le32_to_cpu(here->e_hash);		here = EXT3_XATTR_NEXT(here);	}	header->h_hash = cpu_to_le32(hash);}#undef BLOCK_HASH_SHIFTint __initinit_ext3_xattr(void){	ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,		sizeof(struct mb_cache_entry) +		sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);	if (!ext3_xattr_cache)		return -ENOMEM;	return 0;}voidexit_ext3_xattr(void){	if (ext3_xattr_cache)		mb_cache_destroy(ext3_xattr_cache);	ext3_xattr_cache = NULL;}

⌨️ 快捷键说明

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