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 + -
显示快捷键?