X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Freiserfs%2Fxattr.c;h=cf949646dd574136f0d61dc7eff1387b7e2d0a96;hb=12abb35a03e32c97235fcefdcf2d851be9f82dc2;hp=57920a4df7a4d616fd2fe28912c1e1ff394e0668;hpb=6c17675e1e02ebde220ef639a3fb1333928ec2f4;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 57920a4..cf94964 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -27,6 +27,10 @@ * 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. + * + * Locking works like so: + * Directory components (xattr root, xattr dir) are protectd by their i_mutex. + * The xattrs themselves are protected by the xattr_sem. */ #include @@ -49,20 +53,23 @@ #define PRIVROOT_NAME ".reiserfs_priv" #define XAROOT_NAME "xattrs" + /* Helpers for inode ops. We do this so that we don't have all the VFS * overhead and also for proper i_mutex annotation. * dir->i_mutex must be held for all of them. */ +#ifdef CONFIG_REISERFS_FS_XATTR static int xattr_create(struct inode *dir, struct dentry *dentry, int mode) { BUG_ON(!mutex_is_locked(&dir->i_mutex)); - DQUOT_INIT(dir); + vfs_dq_init(dir); return dir->i_op->create(dir, dentry, mode, NULL); } +#endif static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode) { BUG_ON(!mutex_is_locked(&dir->i_mutex)); - DQUOT_INIT(dir); + vfs_dq_init(dir); return dir->i_op->mkdir(dir, dentry, mode); } @@ -74,7 +81,7 @@ static int xattr_unlink(struct inode *dir, struct dentry *dentry) { int error; BUG_ON(!mutex_is_locked(&dir->i_mutex)); - DQUOT_INIT(dir); + vfs_dq_init(dir); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); error = dir->i_op->unlink(dir, dentry); @@ -89,7 +96,7 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry) { int error; BUG_ON(!mutex_is_locked(&dir->i_mutex)); - DQUOT_INIT(dir); + vfs_dq_init(dir); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); dentry_unhash(dentry); @@ -104,44 +111,30 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry) return error; } - #define xattr_may_create(flags) (!flags || flags & XATTR_CREATE) -/* Returns and possibly creates the xattr dir. */ -static struct dentry *lookup_or_create_dir(struct dentry *parent, - const char *name, int flags) +static struct dentry *open_xa_root(struct super_block *sb, int flags) { - struct dentry *dentry; - BUG_ON(!parent); + struct dentry *privroot = REISERFS_SB(sb)->priv_root; + struct dentry *xaroot; + if (!privroot->d_inode) + return ERR_PTR(-ENODATA); - dentry = lookup_one_len(name, parent, strlen(name)); - if (IS_ERR(dentry)) - return dentry; - else if (!dentry->d_inode) { - int err = -ENODATA; - - if (xattr_may_create(flags)) { - mutex_lock_nested(&parent->d_inode->i_mutex, - I_MUTEX_XATTR); - err = xattr_mkdir(parent->d_inode, dentry, 0700); - mutex_unlock(&parent->d_inode->i_mutex); - } + mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR); + xaroot = dget(REISERFS_SB(sb)->xattr_root); + if (!xaroot->d_inode) { + int err = -ENODATA; + if (xattr_may_create(flags)) + err = xattr_mkdir(privroot->d_inode, xaroot, 0700); if (err) { - dput(dentry); - dentry = ERR_PTR(err); + dput(xaroot); + xaroot = ERR_PTR(err); } } - return dentry; -} - -static struct dentry *open_xa_root(struct super_block *sb, int flags) -{ - struct dentry *privroot = REISERFS_SB(sb)->priv_root; - if (!privroot) - return ERR_PTR(-ENODATA); - return lookup_or_create_dir(privroot, XAROOT_NAME, flags); + mutex_unlock(&privroot->d_inode->i_mutex); + return xaroot; } static struct dentry *open_xa_dir(const struct inode *inode, int flags) @@ -157,372 +150,197 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags) le32_to_cpu(INODE_PKEY(inode)->k_objectid), inode->i_generation); - xadir = lookup_or_create_dir(xaroot, namebuf, flags); - dput(xaroot); - return xadir; - -} - -/* - * 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 inode *inode, void *dirent, filldir_t filldir) -{ - 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_error(inode->i_sb, "jdm-20000", - "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; + mutex_lock_nested(&xaroot->d_inode->i_mutex, I_MUTEX_XATTR); - 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); + xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); + if (!IS_ERR(xadir) && !xadir->d_inode) { + int err = -ENODATA; + if (xattr_may_create(flags)) + err = xattr_mkdir(xaroot->d_inode, xadir, 0700); + if (err) { + dput(xadir); + xadir = ERR_PTR(err); } - } /* while */ + } - end: - pathrelse(&path_to_entry); - return 0; + mutex_unlock(&xaroot->d_inode->i_mutex); + dput(xaroot); + return xadir; } -/* - * 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 - * - */ -static -int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) -{ - int res = -ENOENT; - if (!IS_DEADDIR(inode)) { - lock_kernel(); - res = __xattr_readdir(inode, buf, filler); - unlock_kernel(); - } - return res; -} +/* The following are side effects of other operations that aren't explicitly + * modifying extended attributes. This includes operations such as permissions + * or ownership changes, object deletions, etc. */ +struct reiserfs_dentry_buf { + struct dentry *xadir; + int count; + struct dentry *dentries[8]; +}; static int -__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) +fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset, + u64 ino, unsigned int d_type) { + struct reiserfs_dentry_buf *dbuf = buf; struct dentry *dentry; - struct inode *dir = xadir->d_inode; - int err = 0; + WARN_ON_ONCE(!mutex_is_locked(&dbuf->xadir->d_inode->i_mutex)); + + if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) + return -ENOSPC; + + if (name[0] == '.' && (name[1] == '\0' || + (name[1] == '.' && name[2] == '\0'))) + return 0; - dentry = lookup_one_len(name, xadir, namelen); + dentry = lookup_one_len(name, dbuf->xadir, namelen); if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - goto out; + return PTR_ERR(dentry); } else if (!dentry->d_inode) { - err = -ENODATA; - goto out_file; - } - - /* Skip directories.. */ - if (S_ISDIR(dentry->d_inode->i_mode)) - goto out_file; - - if (!IS_PRIVATE(dentry->d_inode)) { - reiserfs_error(dir->i_sb, "jdm-20003", - "OID %08x [%.*s/%.*s] doesn't have " - "priv flag set [parent is %sset].", - le32_to_cpu(INODE_PKEY(dentry->d_inode)-> - k_objectid), xadir->d_name.len, - xadir->d_name.name, namelen, name, - IS_PRIVATE(xadir->d_inode) ? "" : - "not "); + /* A directory entry exists, but no file? */ + reiserfs_error(dentry->d_sb, "xattr-20003", + "Corrupted directory: xattr %s listed but " + "not found for file %s.\n", + dentry->d_name.name, dbuf->xadir->d_name.name); dput(dentry); return -EIO; } - err = xattr_unlink(dir, dentry); - -out_file: - dput(dentry); - -out: - return err; + dbuf->dentries[dbuf->count++] = dentry; + return 0; } -/* The following are side effects of other operations that aren't explicitly - * modifying extended attributes. This includes operations such as permissions - * or ownership changes, object deletions, etc. */ - -static int -reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static void +cleanup_dentry_buf(struct reiserfs_dentry_buf *buf) { - struct dentry *xadir = (struct dentry *)buf; - - return __reiserfs_xattr_del(xadir, name, namelen); - + int i; + for (i = 0; i < buf->count; i++) + if (buf->dentries[i]) + dput(buf->dentries[i]); } -/* This is called w/ inode->i_mutex downed */ -int reiserfs_delete_xattrs(struct inode *inode) +static int reiserfs_for_each_xattr(struct inode *inode, + int (*action)(struct dentry *, void *), + void *data) { - struct dentry *dir, *root; - int err = 0; + struct dentry *dir; + int i, err = 0; + loff_t pos = 0; + struct reiserfs_dentry_buf buf = { + .count = 0, + }; /* Skip out, an xattr has no xattrs associated with it */ if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) return 0; - reiserfs_read_lock_xattrs(inode->i_sb); dir = open_xa_dir(inode, XATTR_REPLACE); - reiserfs_read_unlock_xattrs(inode->i_sb); if (IS_ERR(dir)) { err = PTR_ERR(dir); goto out; } else if (!dir->d_inode) { - dput(dir); - return 0; + err = 0; + goto out_dir; } mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); - err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); - mutex_unlock(&dir->d_inode->i_mutex); - if (err) - goto out_dir; + buf.xadir = dir; + err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos); + while ((err == 0 || err == -ENOSPC) && buf.count) { + err = 0; + + for (i = 0; i < buf.count && buf.dentries[i]; i++) { + int lerr = 0; + struct dentry *dentry = buf.dentries[i]; - /* Leftovers besides . and .. -- that's not good. */ - if (dir->d_inode->i_nlink <= 2) { - root = open_xa_root(inode->i_sb, XATTR_REPLACE); - reiserfs_write_lock_xattrs(inode->i_sb); - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); - err = xattr_rmdir(root->d_inode, dir); - mutex_unlock(&root->d_inode->i_mutex); - reiserfs_write_unlock_xattrs(inode->i_sb); - dput(root); - } else { - reiserfs_warning(inode->i_sb, "jdm-20006", - "Couldn't remove all entries in directory"); + if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode)) + lerr = action(dentry, data); + + dput(dentry); + buf.dentries[i] = NULL; + err = lerr ?: err; + } + buf.count = 0; + if (!err) + err = reiserfs_readdir_dentry(dir, &buf, + fill_with_dentries, &pos); } + mutex_unlock(&dir->d_inode->i_mutex); + + /* Clean up after a failed readdir */ + cleanup_dentry_buf(&buf); + if (!err) { + /* We start a transaction here to avoid a ABBA situation + * between the xattr root's i_mutex and the journal lock. + * This doesn't incur much additional overhead since the + * new transaction will just nest inside the + * outer transaction. */ + int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + + 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); + struct reiserfs_transaction_handle th; + err = journal_begin(&th, inode->i_sb, blocks); + if (!err) { + int jerror; + mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, + I_MUTEX_XATTR); + err = action(dir, data); + jerror = journal_end(&th, inode->i_sb, blocks); + mutex_unlock(&dir->d_parent->d_inode->i_mutex); + err = jerror ?: err; + } + } out_dir: dput(dir); - out: - if (!err) - REISERFS_I(inode)->i_flags = - REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; + /* -ENODATA isn't an error */ + if (err == -ENODATA) + err = 0; return err; } -struct reiserfs_chown_buf { - struct inode *inode; - struct dentry *xadir; - struct iattr *attrs; -}; - -/* XXX: If there is a better way to do this, I'd love to hear about it */ -static int -reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static int delete_one_xattr(struct dentry *dentry, void *data) { - struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; - struct dentry *xafile, *xadir = chown_buf->xadir; - struct iattr *attrs = chown_buf->attrs; - int err = 0; + struct inode *dir = dentry->d_parent->d_inode; - xafile = lookup_one_len(name, xadir, namelen); - if (IS_ERR(xafile)) - return PTR_ERR(xafile); - else if (!xafile->d_inode) { - dput(xafile); - return -ENODATA; - } + /* This is the xattr dir, handle specially. */ + if (S_ISDIR(dentry->d_inode->i_mode)) + return xattr_rmdir(dir, dentry); - if (!S_ISDIR(xafile->d_inode->i_mode)) { - mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD); - err = notify_change(xafile, attrs); - mutex_unlock(&xafile->d_inode->i_mutex); - } - dput(xafile); + return xattr_unlink(dir, dentry); +} +static int chown_one_xattr(struct dentry *dentry, void *data) +{ + struct iattr *attrs = data; + return reiserfs_setattr(dentry, attrs); +} + +/* No i_mutex, but the inode is unconnected. */ +int reiserfs_delete_xattrs(struct inode *inode) +{ + int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL); + if (err) + reiserfs_warning(inode->i_sb, "jdm-20004", + "Couldn't delete all xattrs (%d)\n", err); return err; } +/* inode->i_mutex: down */ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) { - struct dentry *dir; - int err = 0; - struct reiserfs_chown_buf buf; - unsigned int ia_valid = attrs->ia_valid; - - /* Skip out, an xattr has no xattrs associated with it */ - if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) - return 0; - - reiserfs_read_lock_xattrs(inode->i_sb); - dir = open_xa_dir(inode, XATTR_REPLACE); - reiserfs_read_unlock_xattrs(inode->i_sb); - if (IS_ERR(dir)) { - if (PTR_ERR(dir) != -ENODATA) - err = PTR_ERR(dir); - goto out; - } else if (!dir->d_inode) - goto out_dir; - - attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); - buf.xadir = dir; - buf.attrs = attrs; - buf.inode = inode; - - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); - err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); - - if (!err) - err = notify_change(dir, attrs); - mutex_unlock(&dir->d_inode->i_mutex); - - attrs->ia_valid = ia_valid; -out_dir: - dput(dir); -out: + int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs); + if (err) + reiserfs_warning(inode->i_sb, "jdm-20007", + "Couldn't chown all xattrs (%d)\n", err); return err; } #ifdef CONFIG_REISERFS_FS_XATTR -static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char - *prefix); - /* 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) +static struct dentry *xattr_lookup(struct inode *inode, const char *name, + int flags) { struct dentry *xadir, *xafile; int err = 0; @@ -531,6 +349,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode, if (IS_ERR(xadir)) return ERR_CAST(xadir); + mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR); xafile = lookup_one_len(name, xadir, strlen(name)); if (IS_ERR(xafile)) { err = PTR_ERR(xafile); @@ -542,18 +361,15 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode, if (!xafile->d_inode) { err = -ENODATA; - if (xattr_may_create(flags)) { - mutex_lock_nested(&xadir->d_inode->i_mutex, - I_MUTEX_XATTR); + if (xattr_may_create(flags)) err = xattr_create(xadir->d_inode, xafile, 0700|S_IFREG); - mutex_unlock(&xadir->d_inode->i_mutex); - } } if (err) dput(xafile); out: + mutex_unlock(&xadir->d_inode->i_mutex); dput(xadir); if (err) return ERR_PTR(err); @@ -597,6 +413,45 @@ int reiserfs_commit_write(struct file *f, struct page *page, int reiserfs_prepare_write(struct file *f, struct page *page, unsigned from, unsigned to); +static void update_ctime(struct inode *inode) +{ + struct timespec now = current_fs_time(inode->i_sb); + if (hlist_unhashed(&inode->i_hash) || !inode->i_nlink || + timespec_equal(&inode->i_ctime, &now)) + return; + + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); +} + +static int lookup_and_delete_xattr(struct inode *inode, const char *name) +{ + int err = 0; + struct dentry *dentry, *xadir; + + xadir = open_xa_dir(inode, XATTR_REPLACE); + if (IS_ERR(xadir)) + return PTR_ERR(xadir); + + mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR); + dentry = lookup_one_len(name, xadir, strlen(name)); + if (IS_ERR(dentry)) { + err = PTR_ERR(dentry); + goto out_dput; + } + + if (dentry->d_inode) { + err = xattr_unlink(xadir->d_inode, dentry); + update_ctime(inode); + } + + dput(dentry); +out_dput: + mutex_unlock(&xadir->d_inode->i_mutex); + dput(xadir); + return err; +} + /* Generic extended attribute operations that can be used by xa plugins */ @@ -604,8 +459,9 @@ int reiserfs_prepare_write(struct file *f, struct page *page, * inode->i_mutex: down */ int -reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, - size_t buffer_size, int flags) +reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, + struct inode *inode, const char *name, + const void *buffer, size_t buffer_size, int flags) { int err = 0; struct dentry *dentry; @@ -613,33 +469,22 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, char *data; size_t file_pos = 0; size_t buffer_pos = 0; - struct iattr newattrs; + size_t new_size; __u32 xahash = 0; if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - /* Empty xattrs are ok, they're just empty files, no hash */ - if (buffer && buffer_size) - xahash = xattr_hash(buffer, buffer_size); + if (!buffer) + return lookup_and_delete_xattr(inode, name); - dentry = get_xa_file_dentry(inode, name, flags); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - goto out; - } + dentry = xattr_lookup(inode, name, flags); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); - REISERFS_I(inode)->i_flags |= i_has_xattr_dir; - - /* Resize it so we're ok to write there */ - newattrs.ia_size = buffer_size; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); - err = notify_change(dentry, &newattrs); - mutex_unlock(&dentry->d_inode->i_mutex); - if (err) - goto out_filp; + down_write(&REISERFS_I(inode)->i_xattr_sem); + xahash = xattr_hash(buffer, buffer_size); while (buffer_pos < buffer_size || buffer_pos == 0) { size_t chunk; size_t skip = 0; @@ -652,7 +497,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, page = reiserfs_get_page(dentry->d_inode, file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); - goto out_filp; + goto out_unlock; } lock_page(page); @@ -686,27 +531,61 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, break; } - /* We can't mark the inode dirty if it's not hashed. This is the case - * when we're inheriting the default ACL. If we dirty it, the inode - * gets marked dirty, but won't (ever) make it onto the dirty list until - * it's synced explicitly to clear I_DIRTY. This is bad. */ - if (!hlist_unhashed(&inode->i_hash)) { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); + new_size = buffer_size + sizeof(struct reiserfs_xattr_header); + if (!err && new_size < i_size_read(dentry->d_inode)) { + struct iattr newattrs = { + .ia_ctime = current_fs_time(inode->i_sb), + .ia_size = buffer_size, + .ia_valid = ATTR_SIZE | ATTR_CTIME, + }; + mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); + down_write(&dentry->d_inode->i_alloc_sem); + err = reiserfs_setattr(dentry, &newattrs); + up_write(&dentry->d_inode->i_alloc_sem); + mutex_unlock(&dentry->d_inode->i_mutex); + } else + update_ctime(inode); +out_unlock: + up_write(&REISERFS_I(inode)->i_xattr_sem); + dput(dentry); + return err; +} + +/* We need to start a transaction to maintain lock ordering */ +int reiserfs_xattr_set(struct inode *inode, const char *name, + const void *buffer, size_t buffer_size, int flags) +{ + + struct reiserfs_transaction_handle th; + int error, error2; + size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size); + + if (!(flags & XATTR_REPLACE)) + jbegin_count += reiserfs_xattr_jcreate_nblocks(inode); + + reiserfs_write_lock(inode->i_sb); + error = journal_begin(&th, inode->i_sb, jbegin_count); + if (error) { + reiserfs_write_unlock(inode->i_sb); + return error; } - out_filp: - dput(dentry); + error = reiserfs_xattr_set_handle(&th, inode, name, + buffer, buffer_size, flags); - out: - return err; + error2 = journal_end(&th, inode->i_sb, jbegin_count); + if (error == 0) + error = error2; + reiserfs_write_unlock(inode->i_sb); + + return error; } /* * inode->i_mutex: down */ int -reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, +reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer, size_t buffer_size) { ssize_t err = 0; @@ -725,24 +604,25 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - dentry = get_xa_file_dentry(inode, name, XATTR_REPLACE); + dentry = xattr_lookup(inode, name, XATTR_REPLACE); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out; } + down_read(&REISERFS_I(inode)->i_xattr_sem); + isize = i_size_read(dentry->d_inode); - REISERFS_I(inode)->i_flags |= i_has_xattr_dir; /* Just return the size needed */ if (buffer == NULL) { err = isize - sizeof(struct reiserfs_xattr_header); - goto out_dput; + goto out_unlock; } if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { err = -ERANGE; - goto out_dput; + goto out_unlock; } while (file_pos < isize) { @@ -757,7 +637,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, page = reiserfs_get_page(dentry->d_inode, file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); - goto out_dput; + goto out_unlock; } lock_page(page); @@ -776,7 +656,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, "associated with %k", name, INODE_PKEY(inode)); err = -EIO; - goto out_dput; + goto out_unlock; } hash = le32_to_cpu(rxh->h_hash); } @@ -797,62 +677,63 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, err = -EIO; } -out_dput: +out_unlock: + up_read(&REISERFS_I(inode)->i_xattr_sem); dput(dentry); out: return err; } -int reiserfs_xattr_del(struct inode *inode, const char *name) -{ - struct dentry *dir; - int err; +/* + * In order to implement different sets of xattr operations for each xattr + * prefix with the generic xattr API, a filesystem should create a + * null-terminated array of struct xattr_handler (one for each prefix) and + * hang a pointer to it off of the s_xattr field of the superblock. + * + * The generic_fooxattr() functions will use this list to dispatch xattr + * operations to the correct xattr_handler. + */ +#define for_each_xattr_handler(handlers, handler) \ + for ((handler) = *(handlers)++; \ + (handler) != NULL; \ + (handler) = *(handlers)++) - dir = open_xa_dir(inode, XATTR_REPLACE); - if (IS_ERR(dir)) { - err = PTR_ERR(dir); - goto out; - } +/* This is the implementation for the xattr plugin infrastructure */ +static inline struct xattr_handler * +find_xattr_handler_prefix(struct xattr_handler **handlers, + const char *name) +{ + struct xattr_handler *xah; - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); - err = __reiserfs_xattr_del(dir, name, strlen(name)); - mutex_unlock(&dir->d_inode->i_mutex); - dput(dir); + if (!handlers) + return NULL; - if (!err) { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); + for_each_xattr_handler(handlers, xah) { + if (strncmp(xah->prefix, name, strlen(xah->prefix)) == 0) + break; } - out: - return err; + return xah; } -/* Actual operations that are exported to VFS-land */ -static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char *); /* * Inode operation getxattr() - * Preliminary locking: we down dentry->d_inode->i_mutex */ ssize_t reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, size_t size) { - struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); - int err; + struct inode *inode = dentry->d_inode; + struct xattr_handler *handler; - if (!xah || !reiserfs_xattrs(dentry->d_sb) || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name); + + if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_read_lock_xattr_i(dentry->d_inode); - reiserfs_read_lock_xattrs(dentry->d_sb); - err = xah->get(dentry->d_inode, name, buffer, size); - reiserfs_read_unlock_xattrs(dentry->d_sb); - reiserfs_read_unlock_xattr_i(dentry->d_inode); - return err; + return handler->get(inode, name, buffer, size); } /* @@ -864,27 +745,15 @@ int reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); - int err; - int lock; + struct inode *inode = dentry->d_inode; + struct xattr_handler *handler; - if (!xah || !reiserfs_xattrs(dentry->d_sb) || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name); + + if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_write_lock_xattr_i(dentry->d_inode); - lock = !has_xattr_dir(dentry->d_inode); - if (lock) - reiserfs_write_lock_xattrs(dentry->d_sb); - else - reiserfs_read_lock_xattrs(dentry->d_sb); - err = xah->set(dentry->d_inode, name, value, size, flags); - if (lock) - reiserfs_write_unlock_xattrs(dentry->d_sb); - else - reiserfs_read_unlock_xattrs(dentry->d_sb); - reiserfs_write_unlock_xattr_i(dentry->d_inode); - return err; + return handler->set(inode, name, value, size, flags); } /* @@ -894,233 +763,101 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, */ int reiserfs_removexattr(struct dentry *dentry, const char *name) { - int err; - struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); + struct inode *inode = dentry->d_inode; + struct xattr_handler *handler; + handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name); - if (!xah || !reiserfs_xattrs(dentry->d_sb) || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_write_lock_xattr_i(dentry->d_inode); - reiserfs_read_lock_xattrs(dentry->d_sb); - - /* Deletion pre-operation */ - if (xah->del) { - err = xah->del(dentry->d_inode, name); - if (err) - goto out; - } - - err = reiserfs_xattr_del(dentry->d_inode, name); - - dentry->d_inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(dentry->d_inode); - - out: - reiserfs_read_unlock_xattrs(dentry->d_sb); - reiserfs_write_unlock_xattr_i(dentry->d_inode); - return err; + return handler->set(inode, name, NULL, 0, XATTR_REPLACE); } -/* This is what filldir will use: - * r_pos will always contain the amount of space required for the entire - * list. If r_pos becomes larger than r_size, we need more space and we - * return an error indicating this. If r_pos is less than r_size, then we've - * filled the buffer successfully and we return success */ -struct reiserfs_listxattr_buf { - int r_pos; - int r_size; - char *r_buf; - struct inode *r_inode; +struct listxattr_buf { + size_t size; + size_t pos; + char *buf; + struct inode *inode; }; -static int -reiserfs_listxattr_filler(void *buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static int listxattr_filler(void *buf, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) { - struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf; - int len = 0; - if (name[0] != '.' - || (namelen != 1 && (name[1] != '.' || namelen != 2))) { - struct reiserfs_xattr_handler *xah = - find_xattr_handler_prefix(name); - if (!xah) - return 0; /* Unsupported xattr name, skip it */ - - /* We call ->list() twice because the operation isn't required to just - * return the name back - we want to make sure we have enough space */ - len += xah->list(b->r_inode, name, namelen, NULL); - - if (len) { - if (b->r_pos + len + 1 <= b->r_size) { - char *p = b->r_buf + b->r_pos; - p += xah->list(b->r_inode, name, namelen, p); - *p++ = '\0'; - } - b->r_pos += len + 1; + struct listxattr_buf *b = (struct listxattr_buf *)buf; + size_t size; + if (name[0] != '.' || + (namelen != 1 && (name[1] != '.' || namelen != 2))) { + struct xattr_handler *handler; + handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr, + name); + if (!handler) /* Unsupported xattr name */ + return 0; + if (b->buf) { + size = handler->list(b->inode, b->buf + b->pos, + b->size, name, namelen); + if (size > b->size) + return -ERANGE; + } else { + size = handler->list(b->inode, NULL, 0, name, namelen); } - } + b->pos += size; + } return 0; } /* * Inode operation listxattr() * - * Preliminary locking: we down dentry->d_inode->i_mutex + * We totally ignore the generic listxattr here because it would be stupid + * not to. Since the xattrs are organized in a directory, we can just + * readdir to find them. */ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) { struct dentry *dir; int err = 0; - struct reiserfs_listxattr_buf buf; + loff_t pos = 0; + struct listxattr_buf buf = { + .inode = dentry->d_inode, + .buf = buffer, + .size = buffer ? size : 0, + }; if (!dentry->d_inode) return -EINVAL; - if (!reiserfs_xattrs(dentry->d_sb) || + if (!dentry->d_sb->s_xattr || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) return -EOPNOTSUPP; - reiserfs_read_lock_xattr_i(dentry->d_inode); - reiserfs_read_lock_xattrs(dentry->d_sb); dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); - reiserfs_read_unlock_xattrs(dentry->d_sb); if (IS_ERR(dir)) { err = PTR_ERR(dir); if (err == -ENODATA) - err = 0; /* Not an error if there aren't any xattrs */ + err = 0; /* Not an error if there aren't any xattrs */ goto out; } - buf.r_buf = buffer; - buf.r_size = buffer ? size : 0; - buf.r_pos = 0; - buf.r_inode = dentry->d_inode; - - REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir; - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); - err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf); + err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos); mutex_unlock(&dir->d_inode->i_mutex); - if (err) - goto out_dir; - if (buf.r_pos > buf.r_size && buffer != NULL) - err = -ERANGE; - else - err = buf.r_pos; + if (!err) + err = buf.pos; - out_dir: dput(dir); - - out: - reiserfs_read_unlock_xattr_i(dentry->d_inode); - return err; -} - -/* This is the implementation for the xattr plugin infrastructure */ -static LIST_HEAD(xattr_handlers); -static DEFINE_RWLOCK(handler_lock); - -static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char - *prefix) -{ - struct reiserfs_xattr_handler *xah = NULL; - struct list_head *p; - - read_lock(&handler_lock); - list_for_each(p, &xattr_handlers) { - xah = list_entry(p, struct reiserfs_xattr_handler, handlers); - if (strncmp(xah->prefix, prefix, strlen(xah->prefix)) == 0) - break; - xah = NULL; - } - - read_unlock(&handler_lock); - return xah; -} - -static void __unregister_handlers(void) -{ - struct reiserfs_xattr_handler *xah; - struct list_head *p, *tmp; - - list_for_each_safe(p, tmp, &xattr_handlers) { - xah = list_entry(p, struct reiserfs_xattr_handler, handlers); - if (xah->exit) - xah->exit(); - - list_del_init(p); - } - INIT_LIST_HEAD(&xattr_handlers); -} - -int __init reiserfs_xattr_register_handlers(void) -{ - int err = 0; - struct reiserfs_xattr_handler *xah; - struct list_head *p; - - write_lock(&handler_lock); - - /* If we're already initialized, nothing to do */ - if (!list_empty(&xattr_handlers)) { - write_unlock(&handler_lock); - return 0; - } - - /* Add the handlers */ - list_add_tail(&user_handler.handlers, &xattr_handlers); - list_add_tail(&trusted_handler.handlers, &xattr_handlers); -#ifdef CONFIG_REISERFS_FS_SECURITY - list_add_tail(&security_handler.handlers, &xattr_handlers); -#endif -#ifdef CONFIG_REISERFS_FS_POSIX_ACL - list_add_tail(&posix_acl_access_handler.handlers, &xattr_handlers); - list_add_tail(&posix_acl_default_handler.handlers, &xattr_handlers); -#endif - - /* Run initializers, if available */ - list_for_each(p, &xattr_handlers) { - xah = list_entry(p, struct reiserfs_xattr_handler, handlers); - if (xah->init) { - err = xah->init(); - if (err) { - list_del_init(p); - break; - } - } - } - - /* Clean up other handlers, if any failed */ - if (err) - __unregister_handlers(); - - write_unlock(&handler_lock); +out: return err; } -void reiserfs_xattr_unregister_handlers(void) -{ - write_lock(&handler_lock); - __unregister_handlers(); - write_unlock(&handler_lock); -} - static int reiserfs_check_acl(struct inode *inode, int mask) { struct posix_acl *acl; int error = -EAGAIN; /* do regular unix permission checks by default */ - reiserfs_read_lock_xattr_i(inode); - reiserfs_read_lock_xattrs(inode->i_sb); - acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); - reiserfs_read_unlock_xattrs(inode->i_sb); - reiserfs_read_unlock_xattr_i(inode); - if (acl) { if (!IS_ERR(acl)) { error = posix_acl_permission(inode, acl, mask); @@ -1153,133 +890,147 @@ static int create_privroot(struct dentry *dentry) { int err; struct inode *inode = dentry->d_parent->d_inode; - mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); + WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex)); + err = xattr_mkdir(inode, dentry, 0700); - mutex_unlock(&inode->i_mutex); - if (err) { - dput(dentry); - dentry = NULL; + if (err || !dentry->d_inode) { + reiserfs_warning(dentry->d_sb, "jdm-20006", + "xattrs/ACLs enabled and couldn't " + "find/create .reiserfs_priv. " + "Failing mount."); + return -EOPNOTSUPP; } - if (dentry && dentry->d_inode) - reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " - "storage.\n", PRIVROOT_NAME); + dentry->d_inode->i_flags |= S_PRIVATE; + reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " + "storage.\n", PRIVROOT_NAME); - return err; + return 0; } +#else +int __init reiserfs_xattr_register_handlers(void) { return 0; } +void reiserfs_xattr_unregister_handlers(void) {} +static int create_privroot(struct dentry *dentry) { return 0; } +#endif + +/* Actual operations that are exported to VFS-land */ +struct xattr_handler *reiserfs_xattr_handlers[] = { +#ifdef CONFIG_REISERFS_FS_XATTR + &reiserfs_xattr_user_handler, + &reiserfs_xattr_trusted_handler, +#endif +#ifdef CONFIG_REISERFS_FS_SECURITY + &reiserfs_xattr_security_handler, +#endif +#ifdef CONFIG_REISERFS_FS_POSIX_ACL + &reiserfs_posix_acl_access_handler, + &reiserfs_posix_acl_default_handler, +#endif + NULL +}; + static int xattr_mount_check(struct super_block *s) { /* We need generation numbers to ensure that the oid mapping is correct * v3.5 filesystems don't have them. */ - if (!old_format_only(s)) { - set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); - } else if (reiserfs_xattrs_optional(s)) { - /* Old format filesystem, but optional xattrs have been enabled - * at mount time. Error out. */ - reiserfs_warning(s, "jdm-20005", - "xattrs/ACLs not supported on pre v3.6 " - "format filesystem. Failing mount."); - return -EOPNOTSUPP; - } else { - /* Old format filesystem, but no optional xattrs have - * been enabled. This means we silently disable xattrs - * on the filesystem. */ - clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); + if (old_format_only(s)) { + if (reiserfs_xattrs_optional(s)) { + /* Old format filesystem, but optional xattrs have + * been enabled. Error out. */ + reiserfs_warning(s, "jdm-2005", + "xattrs/ACLs not supported " + "on pre-v3.6 format filesystems. " + "Failing mount."); + return -EOPNOTSUPP; + } } return 0; } -#else -int __init reiserfs_xattr_register_handlers(void) { return 0; } -void reiserfs_xattr_unregister_handlers(void) {} -#endif - /* This will catch lookups from the fs root to .reiserfs_priv */ static int xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) { struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root; - if (name->len == priv_root->d_name.len && - name->hash == priv_root->d_name.hash && - !memcmp(name->name, priv_root->d_name.name, name->len)) { + if (container_of(q1, struct dentry, d_name) == priv_root) return -ENOENT; - } else if (q1->len == name->len && + if (q1->len == name->len && !memcmp(q1->name, name->name, name->len)) return 0; return 1; } -static struct dentry_operations xattr_lookup_poison_ops = { +static const struct dentry_operations xattr_lookup_poison_ops = { .d_compare = xattr_lookup_poison, }; +int reiserfs_lookup_privroot(struct super_block *s) +{ + struct dentry *dentry; + int err = 0; + + /* If we don't have the privroot located yet - go find it */ + mutex_lock(&s->s_root->d_inode->i_mutex); + dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, + strlen(PRIVROOT_NAME)); + if (!IS_ERR(dentry)) { + REISERFS_SB(s)->priv_root = dentry; + s->s_root->d_op = &xattr_lookup_poison_ops; + if (dentry->d_inode) + dentry->d_inode->i_flags |= S_PRIVATE; + } else + err = PTR_ERR(dentry); + mutex_unlock(&s->s_root->d_inode->i_mutex); + + return err; +} + /* We need to take a copy of the mount flags since things like * MS_RDONLY don't get set until *after* we're called. * mount_flags != mount_options */ int reiserfs_xattr_init(struct super_block *s, int mount_flags) { int err = 0; + struct dentry *privroot = REISERFS_SB(s)->priv_root; -#ifdef CONFIG_REISERFS_FS_XATTR err = xattr_mount_check(s); if (err) goto error; -#endif - /* If we don't have the privroot located yet - go find it */ - if (!REISERFS_SB(s)->priv_root) { - struct dentry *dentry; - dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, - strlen(PRIVROOT_NAME)); - if (!IS_ERR(dentry)) { -#ifdef CONFIG_REISERFS_FS_XATTR - if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) - err = create_privroot(dentry); -#endif - if (!dentry->d_inode) { - dput(dentry); - dentry = NULL; - } - } else - err = PTR_ERR(dentry); + if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) { + mutex_lock(&s->s_root->d_inode->i_mutex); + err = create_privroot(REISERFS_SB(s)->priv_root); + mutex_unlock(&s->s_root->d_inode->i_mutex); + } - if (!err && dentry) { - s->s_root->d_op = &xattr_lookup_poison_ops; - dentry->d_inode->i_flags |= S_PRIVATE; - REISERFS_SB(s)->priv_root = dentry; -#ifdef CONFIG_REISERFS_FS_XATTR - /* xattrs are unavailable */ - } else if (!(mount_flags & MS_RDONLY)) { - /* If we're read-only it just means that the dir - * hasn't been created. Not an error -- just no - * xattrs on the fs. We'll check again if we - * go read-write */ - reiserfs_warning(s, "jdm-20006", - "xattrs/ACLs enabled and couldn't " - "find/create .reiserfs_priv. " - "Failing mount."); - err = -EOPNOTSUPP; -#endif + if (privroot->d_inode) { + s->s_xattr = reiserfs_xattr_handlers; + mutex_lock(&privroot->d_inode->i_mutex); + if (!REISERFS_SB(s)->xattr_root) { + struct dentry *dentry; + dentry = lookup_one_len(XAROOT_NAME, privroot, + strlen(XAROOT_NAME)); + if (!IS_ERR(dentry)) + REISERFS_SB(s)->xattr_root = dentry; + else + err = PTR_ERR(dentry); } + mutex_unlock(&privroot->d_inode->i_mutex); } -#ifdef CONFIG_REISERFS_FS_XATTR error: if (err) { - clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt)); } -#endif /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ - s->s_flags = s->s_flags & ~MS_POSIXACL; -#ifdef CONFIG_REISERFS_FS_POSIX_ACL if (reiserfs_posixacl(s)) s->s_flags |= MS_POSIXACL; -#endif + else + s->s_flags &= ~MS_POSIXACL; return err; }