📄 xattr.c
字号:
/* * 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 + -