xattr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,455 行 · 第 1/3 页

C
1,455
字号
/* * 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/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 <linux/mbcache.h>#include <asm/uaccess.h>#include <asm/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);static struct dentry *create_xa_root (struct super_block *sb){    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(-EOPNOTSUPP);    xaroot = lookup_one_len (XAROOT_NAME, privroot, strlen (XAROOT_NAME));    if (IS_ERR (xaroot)) {        goto out;    } else if (!xaroot->d_inode) {        int err;        down (&privroot->d_inode->i_sem);        err = privroot->d_inode->i_op->mkdir (privroot->d_inode, xaroot, 0700);        up (&privroot->d_inode->i_sem);        if (err) {            dput (xaroot);            dput (privroot);            return ERR_PTR (err);        }        REISERFS_SB(sb)->xattr_root = dget (xaroot);    }out:    dput (privroot);    return xaroot;}/* This will return a dentry, or error, refering to the xa root directory. * If the xa root doesn't exist yet, the dentry will be returned without * an associated inode. This dentry can be used with ->mkdir to create * the xa directory. */static struct dentry *__get_xa_root (struct super_block *s){    struct dentry *privroot = dget (REISERFS_SB(s)->priv_root);    struct dentry *xaroot = NULL;    if (IS_ERR (privroot) || !privroot)        return privroot;    xaroot = lookup_one_len (XAROOT_NAME, privroot, strlen (XAROOT_NAME));    if (IS_ERR (xaroot)) {        goto out;    } else if (!xaroot->d_inode) {        dput (xaroot);        xaroot = NULL;        goto out;    }    REISERFS_SB(s)->xattr_root = dget (xaroot);out:    dput (privroot);    return xaroot;}/* Returns the dentry (or NULL) referring to the root of the extended * attribute directory tree. If it has already been retreived, it is used. * Otherwise, we attempt to retreive it from disk. It may also return * a pointer-encoded error. */static inline struct dentry *get_xa_root (struct super_block *s){    struct dentry *dentry = dget (REISERFS_SB(s)->xattr_root);    if (!dentry)        dentry = __get_xa_root (s);    return dentry;}/* 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);    if (IS_ERR (xaroot)) {        return xaroot;    } else if (!xaroot) {        if (flags == 0 || flags & XATTR_CREATE) {            xaroot = create_xa_root (inode->i_sb);            if (IS_ERR (xaroot))                return xaroot;        }        if (!xaroot)            return ERR_PTR (-ENODATA);    }    /* 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);        }        /* Newly created object.. Need to mark it private */        REISERFS_I(xadir->d_inode)->i_flags |= i_priv_object;    }    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_sem 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;        }        /* Newly created object.. Need to mark it private */        REISERFS_I(xafile->d_inode)->i_flags |= i_priv_object;    }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_sem 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_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 = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;	    if (!local_buf) {		pathrelse (&path_to_entry);		return -ENOMEM ;	    }	    if (item_moved (&tmp_ih, &path_to_entry)) {		reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;		/* 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) {		reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;	    }	    goto end;	}	if (local_buf != small_buf) {	    reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;	}    } /* 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_dentry->d_inode;        int res = -ENOTDIR;        if (!file->f_op || !file->f_op->readdir)                goto out;        down(&inode->i_sem);//        down(&inode->i_zombie);        res = -ENOENT;        if (!IS_DEADDIR(inode)) {                lock_kernel();                res = __xattr_readdir(file, buf, filler);                unlock_kernel();        }//        up(&inode->i_zombie);        up(&inode->i_sem);out:        return res;}/* Internal operations on file data */static inline voidreiserfs_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->flags = (mapping->flags & ~__GFP_BITS_MASK) | GFP_NOFS;        page = read_cache_page (mapping, n,                                (filler_t*)mapping->a_ops->readpage, NULL);        if (!IS_ERR(page)) {                wait_on_page_locked(page);                kmap(page);                if (!PageUptodate(page))                        goto fail;                if (PageError(page))                        goto fail;        }        return page;fail:        reiserfs_put_page(page);        return ERR_PTR(-EIO);}static inline __u32xattr_hash (const char *msg, int len){    return csum_partial (msg, len, 0);}/* Generic extended attribute operations that can be used by xa plugins *//*

⌨️ 快捷键说明

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