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

📄 xattr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/fs/reiserfs/xattr.c * * Copyright (c) 2002 by Jeff Mahoney, <jeffm@suse.com> * *//* * In order to implement EA/ACLs in a clean, backwards compatible manner, * they are implemented as files in a "private" directory. * Each EA is in it's own file, with the directory layout like so (/ is assumed * to be relative to fs root). Inside the /.reiserfs_priv/xattrs directory, * directories named using the capital-hex form of the objectid and * generation number are used. Inside each directory are individual files * named with the name of the extended attribute. * * So, for objectid 12648430, we could have: * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_access * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_default * /.reiserfs_priv/xattrs/C0FFEE.0/user.Content-Type * .. or similar. * * The file contents are the text of the EA. The size is known based on the * stat data describing the file. * * In the case of system.posix_acl_access and system.posix_acl_default, since * these are special cases for filesystem ACLs, they are interpreted by the * kernel, in addition, they are negatively and positively cached and attached * to the inode so that unnecessary lookups are avoided. */#include <linux/reiserfs_fs.h>#include <linux/capability.h>#include <linux/dcache.h>#include <linux/namei.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/pagemap.h>#include <linux/xattr.h>#include <linux/reiserfs_xattr.h>#include <linux/reiserfs_acl.h>#include <asm/uaccess.h>#include <net/checksum.h>#include <linux/smp_lock.h>#include <linux/stat.h>#include <asm/semaphore.h>#define FL_READONLY 128#define FL_DIR_SEM_HELD 256#define PRIVROOT_NAME ".reiserfs_priv"#define XAROOT_NAME   "xattrs"static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char								*prefix);/* Returns the dentry referring to the root of the extended attribute * directory tree. If it has already been retrieved, it is used. If it * hasn't been created and the flags indicate creation is allowed, we * attempt to create it. On error, we return a pointer-encoded error. */static struct dentry *get_xa_root(struct super_block *sb, int flags){	struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root);	struct dentry *xaroot;	/* This needs to be created at mount-time */	if (!privroot)		return ERR_PTR(-ENODATA);	mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR);	if (REISERFS_SB(sb)->xattr_root) {		xaroot = dget(REISERFS_SB(sb)->xattr_root);		goto out;	}	xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));	if (IS_ERR(xaroot)) {		goto out;	} else if (!xaroot->d_inode) {		int err = -ENODATA;		if (flags == 0 || flags & XATTR_CREATE)			err = privroot->d_inode->i_op->mkdir(privroot->d_inode,			                                     xaroot, 0700);		if (err) {			dput(xaroot);			xaroot = ERR_PTR(err);			goto out;		}	}	REISERFS_SB(sb)->xattr_root = dget(xaroot);      out:	mutex_unlock(&privroot->d_inode->i_mutex);	dput(privroot);	return xaroot;}/* Opens the directory corresponding to the inode's extended attribute store. * If flags allow, the tree to the directory may be created. If creation is * prohibited, -ENODATA is returned. */static struct dentry *open_xa_dir(const struct inode *inode, int flags){	struct dentry *xaroot, *xadir;	char namebuf[17];	xaroot = get_xa_root(inode->i_sb, flags);	if (IS_ERR(xaroot))		return xaroot;	/* ok, we have xaroot open */	snprintf(namebuf, sizeof(namebuf), "%X.%X",		 le32_to_cpu(INODE_PKEY(inode)->k_objectid),		 inode->i_generation);	xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf));	if (IS_ERR(xadir)) {		dput(xaroot);		return xadir;	}	if (!xadir->d_inode) {		int err;		if (flags == 0 || flags & XATTR_CREATE) {			/* Although there is nothing else trying to create this directory,			 * another directory with the same hash may be created, so we need			 * to protect against that */			err =			    xaroot->d_inode->i_op->mkdir(xaroot->d_inode, xadir,							 0700);			if (err) {				dput(xaroot);				dput(xadir);				return ERR_PTR(err);			}		}		if (!xadir->d_inode) {			dput(xaroot);			dput(xadir);			return ERR_PTR(-ENODATA);		}	}	dput(xaroot);	return xadir;}/* Returns a dentry corresponding to a specific extended attribute file * for the inode. If flags allow, the file is created. Otherwise, a * valid or negative dentry, or an error is returned. */static struct dentry *get_xa_file_dentry(const struct inode *inode,					 const char *name, int flags){	struct dentry *xadir, *xafile;	int err = 0;	xadir = open_xa_dir(inode, flags);	if (IS_ERR(xadir)) {		return ERR_PTR(PTR_ERR(xadir));	} else if (xadir && !xadir->d_inode) {		dput(xadir);		return ERR_PTR(-ENODATA);	}	xafile = lookup_one_len(name, xadir, strlen(name));	if (IS_ERR(xafile)) {		dput(xadir);		return ERR_PTR(PTR_ERR(xafile));	}	if (xafile->d_inode) {	/* file exists */		if (flags & XATTR_CREATE) {			err = -EEXIST;			dput(xafile);			goto out;		}	} else if (flags & XATTR_REPLACE || flags & FL_READONLY) {		goto out;	} else {		/* inode->i_mutex is down, so nothing else can try to create		 * the same xattr */		err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,						   0700 | S_IFREG, NULL);		if (err) {			dput(xafile);			goto out;		}	}      out:	dput(xadir);	if (err)		xafile = ERR_PTR(err);	return xafile;}/* Opens a file pointer to the attribute associated with inode */static struct file *open_xa_file(const struct inode *inode, const char *name,				 int flags){	struct dentry *xafile;	struct file *fp;	xafile = get_xa_file_dentry(inode, name, flags);	if (IS_ERR(xafile))		return ERR_PTR(PTR_ERR(xafile));	else if (!xafile->d_inode) {		dput(xafile);		return ERR_PTR(-ENODATA);	}	fp = dentry_open(xafile, NULL, O_RDWR);	/* dentry_open dputs the dentry if it fails */	return fp;}/* * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but * we need to drop the path before calling the filldir struct.  That * would be a big performance hit to the non-xattr case, so I've copied * the whole thing for now. --clm * * the big difference is that I go backwards through the directory, * and don't mess with f->f_pos, but the idea is the same.  Do some * action on each and every entry in the directory. * * we're called with i_mutex held, so there are no worries about the directory * changing underneath us. */static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct inode *inode = filp->f_path.dentry->d_inode;	struct cpu_key pos_key;	/* key of current position in the directory (key of directory entry) */	INITIALIZE_PATH(path_to_entry);	struct buffer_head *bh;	int entry_num;	struct item_head *ih, tmp_ih;	int search_res;	char *local_buf;	loff_t next_pos;	char small_buf[32];	/* avoid kmalloc if we can */	struct reiserfs_de_head *deh;	int d_reclen;	char *d_name;	off_t d_off;	ino_t d_ino;	struct reiserfs_dir_entry de;	/* form key for search the next directory entry using f_pos field of	   file structure */	next_pos = max_reiserfs_offset(inode);	while (1) {	      research:		if (next_pos <= DOT_DOT_OFFSET)			break;		make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3);		search_res =		    search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,					&de);		if (search_res == IO_ERROR) {			// FIXME: we could just skip part of directory which could			// not be read			pathrelse(&path_to_entry);			return -EIO;		}		if (search_res == NAME_NOT_FOUND)			de.de_entry_num--;		set_de_name_and_namelen(&de);		entry_num = de.de_entry_num;		deh = &(de.de_deh[entry_num]);		bh = de.de_bh;		ih = de.de_ih;		if (!is_direntry_le_ih(ih)) {			reiserfs_warning(inode->i_sb, "not direntry %h", ih);			break;		}		copy_item_head(&tmp_ih, ih);		/* we must have found item, that is item of this directory, */		RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),		       "vs-9000: found item %h does not match to dir we readdir %K",		       ih, &pos_key);		if (deh_offset(deh) <= DOT_DOT_OFFSET) {			break;		}		/* look for the previous entry in the directory */		next_pos = deh_offset(deh) - 1;		if (!de_visible(deh))			/* it is hidden entry */			continue;		d_reclen = entry_length(bh, ih, entry_num);		d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);		d_off = deh_offset(deh);		d_ino = deh_objectid(deh);		if (!d_name[d_reclen - 1])			d_reclen = strlen(d_name);		if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) {			/* too big to send back to VFS */			continue;		}		/* Ignore the .reiserfs_priv entry */		if (reiserfs_xattrs(inode->i_sb) &&		    !old_format_only(inode->i_sb) &&		    deh_objectid(deh) ==		    le32_to_cpu(INODE_PKEY				(REISERFS_SB(inode->i_sb)->priv_root->d_inode)->				k_objectid))			continue;		if (d_reclen <= 32) {			local_buf = small_buf;		} else {			local_buf = kmalloc(d_reclen, GFP_NOFS);			if (!local_buf) {				pathrelse(&path_to_entry);				return -ENOMEM;			}			if (item_moved(&tmp_ih, &path_to_entry)) {				kfree(local_buf);				/* sigh, must retry.  Do this same offset again */				next_pos = d_off;				goto research;			}		}		// Note, that we copy name to user space via temporary		// buffer (local_buf) because filldir will block if		// user space buffer is swapped out. At that time		// entry can move to somewhere else		memcpy(local_buf, d_name, d_reclen);		/* the filldir function might need to start transactions,		 * or do who knows what.  Release the path now that we've		 * copied all the important stuff out of the deh		 */		pathrelse(&path_to_entry);		if (filldir(dirent, local_buf, d_reclen, d_off, d_ino,			    DT_UNKNOWN) < 0) {			if (local_buf != small_buf) {				kfree(local_buf);			}			goto end;		}		if (local_buf != small_buf) {			kfree(local_buf);		}	}			/* while */      end:	pathrelse(&path_to_entry);	return 0;}/* * this could be done with dedicated readdir ops for the xattr files, * but I want to get something working asap * this is stolen from vfs_readdir * */staticint xattr_readdir(struct file *file, filldir_t filler, void *buf){	struct inode *inode = file->f_path.dentry->d_inode;	int res = -ENOTDIR;	if (!file->f_op || !file->f_op->readdir)		goto out;	mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);//        down(&inode->i_zombie);	res = -ENOENT;	if (!IS_DEADDIR(inode)) {		lock_kernel();		res = __xattr_readdir(file, buf, filler);		unlock_kernel();	}//        up(&inode->i_zombie);	mutex_unlock(&inode->i_mutex);      out:	return res;}/* Internal operations on file data */static inline void reiserfs_put_page(struct page *page){	kunmap(page);	page_cache_release(page);}static struct page *reiserfs_get_page(struct inode *dir, unsigned long n){	struct address_space *mapping = dir->i_mapping;	struct page *page;	/* We can deadlock if we try to free dentries,	   and an unlink/rmdir has just occured - GFP_NOFS avoids this */	mapping_set_gfp_mask(mapping, GFP_NOFS);	page = read_mapping_page(mapping, n, NULL);	if (!IS_ERR(page)) {		kmap(page);		if (PageError(page))			goto fail;	}	return page;      fail:	reiserfs_put_page(page);	return ERR_PTR(-EIO);}static inline __u32 xattr_hash(const char *msg, int len){	return csum_partial(msg, len, 0);}int reiserfs_commit_write(struct file *f, struct page *page,			  unsigned from, unsigned to);int reiserfs_prepare_write(struct file *f, struct page *page,			   unsigned from, unsigned to);/* Generic extended attribute operations that can be used by xa plugins *//* * inode->i_mutex: down */intreiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,

⌨️ 快捷键说明

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