| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * linux/fs/reiserfs/xattr.c | 
|  | 3 | * | 
|  | 4 | * Copyright (c) 2002 by Jeff Mahoney, <jeffm@suse.com> | 
|  | 5 | * | 
|  | 6 | */ | 
|  | 7 |  | 
|  | 8 | /* | 
|  | 9 | * In order to implement EA/ACLs in a clean, backwards compatible manner, | 
|  | 10 | * they are implemented as files in a "private" directory. | 
|  | 11 | * Each EA is in it's own file, with the directory layout like so (/ is assumed | 
|  | 12 | * to be relative to fs root). Inside the /.reiserfs_priv/xattrs directory, | 
|  | 13 | * directories named using the capital-hex form of the objectid and | 
|  | 14 | * generation number are used. Inside each directory are individual files | 
|  | 15 | * named with the name of the extended attribute. | 
|  | 16 | * | 
|  | 17 | * So, for objectid 12648430, we could have: | 
|  | 18 | * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_access | 
|  | 19 | * /.reiserfs_priv/xattrs/C0FFEE.0/system.posix_acl_default | 
|  | 20 | * /.reiserfs_priv/xattrs/C0FFEE.0/user.Content-Type | 
|  | 21 | * .. or similar. | 
|  | 22 | * | 
|  | 23 | * The file contents are the text of the EA. The size is known based on the | 
|  | 24 | * stat data describing the file. | 
|  | 25 | * | 
|  | 26 | * In the case of system.posix_acl_access and system.posix_acl_default, since | 
|  | 27 | * these are special cases for filesystem ACLs, they are interpreted by the | 
|  | 28 | * kernel, in addition, they are negatively and positively cached and attached | 
|  | 29 | * to the inode so that unnecessary lookups are avoided. | 
|  | 30 | */ | 
|  | 31 |  | 
|  | 32 | #include <linux/reiserfs_fs.h> | 
| Randy Dunlap | 16f7e0f | 2006-01-11 12:17:46 -0800 | [diff] [blame] | 33 | #include <linux/capability.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | #include <linux/dcache.h> | 
|  | 35 | #include <linux/namei.h> | 
|  | 36 | #include <linux/errno.h> | 
|  | 37 | #include <linux/fs.h> | 
|  | 38 | #include <linux/file.h> | 
|  | 39 | #include <linux/pagemap.h> | 
|  | 40 | #include <linux/xattr.h> | 
|  | 41 | #include <linux/reiserfs_xattr.h> | 
|  | 42 | #include <linux/reiserfs_acl.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | #include <asm/uaccess.h> | 
|  | 44 | #include <asm/checksum.h> | 
|  | 45 | #include <linux/smp_lock.h> | 
|  | 46 | #include <linux/stat.h> | 
|  | 47 | #include <asm/semaphore.h> | 
|  | 48 |  | 
|  | 49 | #define FL_READONLY 128 | 
|  | 50 | #define FL_DIR_SEM_HELD 256 | 
|  | 51 | #define PRIVROOT_NAME ".reiserfs_priv" | 
|  | 52 | #define XAROOT_NAME   "xattrs" | 
|  | 53 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 54 | static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char | 
|  | 55 | *prefix); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 57 | static struct dentry *create_xa_root(struct super_block *sb) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 59 | struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root); | 
|  | 60 | struct dentry *xaroot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 62 | /* This needs to be created at mount-time */ | 
|  | 63 | if (!privroot) | 
|  | 64 | return ERR_PTR(-EOPNOTSUPP); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 66 | xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME)); | 
|  | 67 | if (IS_ERR(xaroot)) { | 
|  | 68 | goto out; | 
|  | 69 | } else if (!xaroot->d_inode) { | 
|  | 70 | int err; | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 71 | mutex_lock(&privroot->d_inode->i_mutex); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 72 | err = | 
|  | 73 | privroot->d_inode->i_op->mkdir(privroot->d_inode, xaroot, | 
|  | 74 | 0700); | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 75 | mutex_unlock(&privroot->d_inode->i_mutex); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 77 | if (err) { | 
|  | 78 | dput(xaroot); | 
|  | 79 | dput(privroot); | 
|  | 80 | return ERR_PTR(err); | 
|  | 81 | } | 
|  | 82 | REISERFS_SB(sb)->xattr_root = dget(xaroot); | 
|  | 83 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 85 | out: | 
|  | 86 | dput(privroot); | 
|  | 87 | return xaroot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | } | 
|  | 89 |  | 
|  | 90 | /* This will return a dentry, or error, refering to the xa root directory. | 
|  | 91 | * If the xa root doesn't exist yet, the dentry will be returned without | 
|  | 92 | * an associated inode. This dentry can be used with ->mkdir to create | 
|  | 93 | * the xa directory. */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 94 | static struct dentry *__get_xa_root(struct super_block *s) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 96 | struct dentry *privroot = dget(REISERFS_SB(s)->priv_root); | 
|  | 97 | struct dentry *xaroot = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 98 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 99 | if (IS_ERR(privroot) || !privroot) | 
|  | 100 | return privroot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 102 | xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME)); | 
|  | 103 | if (IS_ERR(xaroot)) { | 
|  | 104 | goto out; | 
|  | 105 | } else if (!xaroot->d_inode) { | 
|  | 106 | dput(xaroot); | 
|  | 107 | xaroot = NULL; | 
|  | 108 | goto out; | 
|  | 109 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 111 | REISERFS_SB(s)->xattr_root = dget(xaroot); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 113 | out: | 
|  | 114 | dput(privroot); | 
|  | 115 | return xaroot; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | } | 
|  | 117 |  | 
|  | 118 | /* Returns the dentry (or NULL) referring to the root of the extended | 
| Matt Mackall | 4a4efbd | 2006-01-03 13:27:11 +0100 | [diff] [blame] | 119 | * attribute directory tree. If it has already been retrieved, it is used. | 
|  | 120 | * Otherwise, we attempt to retrieve it from disk. It may also return | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | * a pointer-encoded error. | 
|  | 122 | */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 123 | static inline struct dentry *get_xa_root(struct super_block *s) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 124 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 125 | struct dentry *dentry = dget(REISERFS_SB(s)->xattr_root); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 127 | if (!dentry) | 
|  | 128 | dentry = __get_xa_root(s); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 130 | return dentry; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | } | 
|  | 132 |  | 
|  | 133 | /* Opens the directory corresponding to the inode's extended attribute store. | 
|  | 134 | * If flags allow, the tree to the directory may be created. If creation is | 
|  | 135 | * prohibited, -ENODATA is returned. */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 136 | static struct dentry *open_xa_dir(const struct inode *inode, int flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 138 | struct dentry *xaroot, *xadir; | 
|  | 139 | char namebuf[17]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 141 | xaroot = get_xa_root(inode->i_sb); | 
|  | 142 | if (IS_ERR(xaroot)) { | 
|  | 143 | return xaroot; | 
|  | 144 | } else if (!xaroot) { | 
|  | 145 | if (flags == 0 || flags & XATTR_CREATE) { | 
|  | 146 | xaroot = create_xa_root(inode->i_sb); | 
|  | 147 | if (IS_ERR(xaroot)) | 
|  | 148 | return xaroot; | 
|  | 149 | } | 
|  | 150 | if (!xaroot) | 
|  | 151 | return ERR_PTR(-ENODATA); | 
|  | 152 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 154 | /* ok, we have xaroot open */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 156 | snprintf(namebuf, sizeof(namebuf), "%X.%X", | 
|  | 157 | le32_to_cpu(INODE_PKEY(inode)->k_objectid), | 
|  | 158 | inode->i_generation); | 
|  | 159 | xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); | 
|  | 160 | if (IS_ERR(xadir)) { | 
|  | 161 | dput(xaroot); | 
|  | 162 | return xadir; | 
|  | 163 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 164 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 165 | if (!xadir->d_inode) { | 
|  | 166 | int err; | 
|  | 167 | if (flags == 0 || flags & XATTR_CREATE) { | 
|  | 168 | /* Although there is nothing else trying to create this directory, | 
|  | 169 | * another directory with the same hash may be created, so we need | 
|  | 170 | * to protect against that */ | 
|  | 171 | err = | 
|  | 172 | xaroot->d_inode->i_op->mkdir(xaroot->d_inode, xadir, | 
|  | 173 | 0700); | 
|  | 174 | if (err) { | 
|  | 175 | dput(xaroot); | 
|  | 176 | dput(xadir); | 
|  | 177 | return ERR_PTR(err); | 
|  | 178 | } | 
|  | 179 | } | 
|  | 180 | if (!xadir->d_inode) { | 
|  | 181 | dput(xaroot); | 
|  | 182 | dput(xadir); | 
|  | 183 | return ERR_PTR(-ENODATA); | 
|  | 184 | } | 
|  | 185 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 187 | dput(xaroot); | 
|  | 188 | return xadir; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
|  | 191 | /* Returns a dentry corresponding to a specific extended attribute file | 
|  | 192 | * for the inode. If flags allow, the file is created. Otherwise, a | 
|  | 193 | * valid or negative dentry, or an error is returned. */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 194 | static struct dentry *get_xa_file_dentry(const struct inode *inode, | 
|  | 195 | const char *name, int flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 197 | struct dentry *xadir, *xafile; | 
|  | 198 | int err = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 200 | xadir = open_xa_dir(inode, flags); | 
|  | 201 | if (IS_ERR(xadir)) { | 
|  | 202 | return ERR_PTR(PTR_ERR(xadir)); | 
|  | 203 | } else if (xadir && !xadir->d_inode) { | 
|  | 204 | dput(xadir); | 
|  | 205 | return ERR_PTR(-ENODATA); | 
|  | 206 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 208 | xafile = lookup_one_len(name, xadir, strlen(name)); | 
|  | 209 | if (IS_ERR(xafile)) { | 
|  | 210 | dput(xadir); | 
|  | 211 | return ERR_PTR(PTR_ERR(xafile)); | 
|  | 212 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 213 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 214 | if (xafile->d_inode) {	/* file exists */ | 
|  | 215 | if (flags & XATTR_CREATE) { | 
|  | 216 | err = -EEXIST; | 
|  | 217 | dput(xafile); | 
|  | 218 | goto out; | 
|  | 219 | } | 
|  | 220 | } else if (flags & XATTR_REPLACE || flags & FL_READONLY) { | 
|  | 221 | goto out; | 
|  | 222 | } else { | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 223 | /* inode->i_mutex is down, so nothing else can try to create | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 224 | * the same xattr */ | 
|  | 225 | err = xadir->d_inode->i_op->create(xadir->d_inode, xafile, | 
|  | 226 | 0700 | S_IFREG, NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 227 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 228 | if (err) { | 
|  | 229 | dput(xafile); | 
|  | 230 | goto out; | 
|  | 231 | } | 
|  | 232 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 233 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 234 | out: | 
|  | 235 | dput(xadir); | 
|  | 236 | if (err) | 
|  | 237 | xafile = ERR_PTR(err); | 
|  | 238 | return xafile; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 239 | } | 
|  | 240 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 241 | /* Opens a file pointer to the attribute associated with inode */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 242 | static struct file *open_xa_file(const struct inode *inode, const char *name, | 
|  | 243 | int flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 244 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 245 | struct dentry *xafile; | 
|  | 246 | struct file *fp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 247 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 248 | xafile = get_xa_file_dentry(inode, name, flags); | 
|  | 249 | if (IS_ERR(xafile)) | 
|  | 250 | return ERR_PTR(PTR_ERR(xafile)); | 
|  | 251 | else if (!xafile->d_inode) { | 
|  | 252 | dput(xafile); | 
|  | 253 | return ERR_PTR(-ENODATA); | 
|  | 254 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 256 | fp = dentry_open(xafile, NULL, O_RDWR); | 
|  | 257 | /* dentry_open dputs the dentry if it fails */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 258 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 259 | return fp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 260 | } | 
|  | 261 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 262 | /* | 
|  | 263 | * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but | 
|  | 264 | * we need to drop the path before calling the filldir struct.  That | 
|  | 265 | * would be a big performance hit to the non-xattr case, so I've copied | 
|  | 266 | * the whole thing for now. --clm | 
|  | 267 | * | 
|  | 268 | * the big difference is that I go backwards through the directory, | 
|  | 269 | * and don't mess with f->f_pos, but the idea is the same.  Do some | 
|  | 270 | * action on each and every entry in the directory. | 
|  | 271 | * | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 272 | * we're called with i_mutex held, so there are no worries about the directory | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 273 | * changing underneath us. | 
|  | 274 | */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 275 | static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 277 | struct inode *inode = filp->f_dentry->d_inode; | 
|  | 278 | struct cpu_key pos_key;	/* key of current position in the directory (key of directory entry) */ | 
|  | 279 | INITIALIZE_PATH(path_to_entry); | 
|  | 280 | struct buffer_head *bh; | 
|  | 281 | int entry_num; | 
|  | 282 | struct item_head *ih, tmp_ih; | 
|  | 283 | int search_res; | 
|  | 284 | char *local_buf; | 
|  | 285 | loff_t next_pos; | 
|  | 286 | char small_buf[32];	/* avoid kmalloc if we can */ | 
|  | 287 | struct reiserfs_de_head *deh; | 
|  | 288 | int d_reclen; | 
|  | 289 | char *d_name; | 
|  | 290 | off_t d_off; | 
|  | 291 | ino_t d_ino; | 
|  | 292 | struct reiserfs_dir_entry de; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 293 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 294 | /* form key for search the next directory entry using f_pos field of | 
|  | 295 | file structure */ | 
|  | 296 | next_pos = max_reiserfs_offset(inode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 298 | while (1) { | 
|  | 299 | research: | 
|  | 300 | if (next_pos <= DOT_DOT_OFFSET) | 
|  | 301 | break; | 
|  | 302 | make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 304 | search_res = | 
|  | 305 | search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, | 
|  | 306 | &de); | 
|  | 307 | if (search_res == IO_ERROR) { | 
|  | 308 | // FIXME: we could just skip part of directory which could | 
|  | 309 | // not be read | 
|  | 310 | pathrelse(&path_to_entry); | 
|  | 311 | return -EIO; | 
|  | 312 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 314 | if (search_res == NAME_NOT_FOUND) | 
|  | 315 | de.de_entry_num--; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 317 | set_de_name_and_namelen(&de); | 
|  | 318 | entry_num = de.de_entry_num; | 
|  | 319 | deh = &(de.de_deh[entry_num]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 321 | bh = de.de_bh; | 
|  | 322 | ih = de.de_ih; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 323 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 324 | if (!is_direntry_le_ih(ih)) { | 
|  | 325 | reiserfs_warning(inode->i_sb, "not direntry %h", ih); | 
|  | 326 | break; | 
|  | 327 | } | 
|  | 328 | copy_item_head(&tmp_ih, ih); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 329 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 330 | /* we must have found item, that is item of this directory, */ | 
|  | 331 | RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key), | 
|  | 332 | "vs-9000: found item %h does not match to dir we readdir %K", | 
|  | 333 | ih, &pos_key); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 334 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 335 | if (deh_offset(deh) <= DOT_DOT_OFFSET) { | 
|  | 336 | break; | 
|  | 337 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 338 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 339 | /* look for the previous entry in the directory */ | 
|  | 340 | next_pos = deh_offset(deh) - 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 341 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 342 | if (!de_visible(deh)) | 
|  | 343 | /* it is hidden entry */ | 
|  | 344 | continue; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 345 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 346 | d_reclen = entry_length(bh, ih, entry_num); | 
|  | 347 | d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); | 
|  | 348 | d_off = deh_offset(deh); | 
|  | 349 | d_ino = deh_objectid(deh); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 351 | if (!d_name[d_reclen - 1]) | 
|  | 352 | d_reclen = strlen(d_name); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 353 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 354 | if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) { | 
|  | 355 | /* too big to send back to VFS */ | 
|  | 356 | continue; | 
|  | 357 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 358 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 359 | /* Ignore the .reiserfs_priv entry */ | 
|  | 360 | if (reiserfs_xattrs(inode->i_sb) && | 
|  | 361 | !old_format_only(inode->i_sb) && | 
|  | 362 | deh_objectid(deh) == | 
|  | 363 | le32_to_cpu(INODE_PKEY | 
|  | 364 | (REISERFS_SB(inode->i_sb)->priv_root->d_inode)-> | 
|  | 365 | k_objectid)) | 
|  | 366 | continue; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 367 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 368 | if (d_reclen <= 32) { | 
|  | 369 | local_buf = small_buf; | 
|  | 370 | } else { | 
| Pekka Enberg | d739b42 | 2006-02-01 03:06:43 -0800 | [diff] [blame] | 371 | local_buf = kmalloc(d_reclen, GFP_NOFS); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 372 | if (!local_buf) { | 
|  | 373 | pathrelse(&path_to_entry); | 
|  | 374 | return -ENOMEM; | 
|  | 375 | } | 
|  | 376 | if (item_moved(&tmp_ih, &path_to_entry)) { | 
| Pekka Enberg | d739b42 | 2006-02-01 03:06:43 -0800 | [diff] [blame] | 377 | kfree(local_buf); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 378 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 379 | /* sigh, must retry.  Do this same offset again */ | 
|  | 380 | next_pos = d_off; | 
|  | 381 | goto research; | 
|  | 382 | } | 
|  | 383 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 384 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 385 | // Note, that we copy name to user space via temporary | 
|  | 386 | // buffer (local_buf) because filldir will block if | 
|  | 387 | // user space buffer is swapped out. At that time | 
|  | 388 | // entry can move to somewhere else | 
|  | 389 | memcpy(local_buf, d_name, d_reclen); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 390 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 391 | /* the filldir function might need to start transactions, | 
|  | 392 | * or do who knows what.  Release the path now that we've | 
|  | 393 | * copied all the important stuff out of the deh | 
|  | 394 | */ | 
|  | 395 | pathrelse(&path_to_entry); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 396 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 397 | if (filldir(dirent, local_buf, d_reclen, d_off, d_ino, | 
|  | 398 | DT_UNKNOWN) < 0) { | 
|  | 399 | if (local_buf != small_buf) { | 
| Pekka Enberg | d739b42 | 2006-02-01 03:06:43 -0800 | [diff] [blame] | 400 | kfree(local_buf); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 401 | } | 
|  | 402 | goto end; | 
|  | 403 | } | 
|  | 404 | if (local_buf != small_buf) { | 
| Pekka Enberg | d739b42 | 2006-02-01 03:06:43 -0800 | [diff] [blame] | 405 | kfree(local_buf); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 406 | } | 
|  | 407 | }			/* while */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 408 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 409 | end: | 
|  | 410 | pathrelse(&path_to_entry); | 
|  | 411 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 412 | } | 
|  | 413 |  | 
|  | 414 | /* | 
|  | 415 | * this could be done with dedicated readdir ops for the xattr files, | 
|  | 416 | * but I want to get something working asap | 
|  | 417 | * this is stolen from vfs_readdir | 
|  | 418 | * | 
|  | 419 | */ | 
|  | 420 | static | 
|  | 421 | int xattr_readdir(struct file *file, filldir_t filler, void *buf) | 
|  | 422 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 423 | struct inode *inode = file->f_dentry->d_inode; | 
|  | 424 | int res = -ENOTDIR; | 
|  | 425 | if (!file->f_op || !file->f_op->readdir) | 
|  | 426 | goto out; | 
| Ingo Molnar | 4df4624 | 2006-08-27 01:23:56 -0700 | [diff] [blame] | 427 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 428 | //        down(&inode->i_zombie); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 429 | res = -ENOENT; | 
|  | 430 | if (!IS_DEADDIR(inode)) { | 
|  | 431 | lock_kernel(); | 
|  | 432 | res = __xattr_readdir(file, buf, filler); | 
|  | 433 | unlock_kernel(); | 
|  | 434 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 435 | //        up(&inode->i_zombie); | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 436 | mutex_unlock(&inode->i_mutex); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 437 | out: | 
|  | 438 | return res; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 439 | } | 
|  | 440 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 441 | /* Internal operations on file data */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 442 | static inline void reiserfs_put_page(struct page *page) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 443 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 444 | kunmap(page); | 
|  | 445 | page_cache_release(page); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 446 | } | 
|  | 447 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 448 | static struct page *reiserfs_get_page(struct inode *dir, unsigned long n) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 449 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 450 | struct address_space *mapping = dir->i_mapping; | 
|  | 451 | struct page *page; | 
|  | 452 | /* We can deadlock if we try to free dentries, | 
|  | 453 | and an unlink/rmdir has just occured - GFP_NOFS avoids this */ | 
| Al Viro | c4cdd038 | 2005-10-21 03:22:39 -0400 | [diff] [blame] | 454 | mapping_set_gfp_mask(mapping, GFP_NOFS); | 
| Pekka Enberg | 090d2b1 | 2006-06-23 02:05:08 -0700 | [diff] [blame] | 455 | page = read_mapping_page(mapping, n, NULL); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 456 | if (!IS_ERR(page)) { | 
|  | 457 | wait_on_page_locked(page); | 
|  | 458 | kmap(page); | 
|  | 459 | if (!PageUptodate(page)) | 
|  | 460 | goto fail; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 461 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 462 | if (PageError(page)) | 
|  | 463 | goto fail; | 
|  | 464 | } | 
|  | 465 | return page; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 466 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 467 | fail: | 
|  | 468 | reiserfs_put_page(page); | 
|  | 469 | return ERR_PTR(-EIO); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 470 | } | 
|  | 471 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 472 | static inline __u32 xattr_hash(const char *msg, int len) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 473 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 474 | return csum_partial(msg, len, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 475 | } | 
|  | 476 |  | 
|  | 477 | /* Generic extended attribute operations that can be used by xa plugins */ | 
|  | 478 |  | 
|  | 479 | /* | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 480 | * inode->i_mutex: down | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 481 | */ | 
|  | 482 | int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 483 | reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, | 
|  | 484 | size_t buffer_size, int flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 485 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 486 | int err = 0; | 
|  | 487 | struct file *fp; | 
|  | 488 | struct page *page; | 
|  | 489 | char *data; | 
|  | 490 | struct address_space *mapping; | 
|  | 491 | size_t file_pos = 0; | 
|  | 492 | size_t buffer_pos = 0; | 
|  | 493 | struct inode *xinode; | 
|  | 494 | struct iattr newattrs; | 
|  | 495 | __u32 xahash = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 496 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 497 | if (get_inode_sd_version(inode) == STAT_DATA_V1) | 
|  | 498 | return -EOPNOTSUPP; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 499 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 500 | /* Empty xattrs are ok, they're just empty files, no hash */ | 
|  | 501 | if (buffer && buffer_size) | 
|  | 502 | xahash = xattr_hash(buffer, buffer_size); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 503 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 504 | open_file: | 
|  | 505 | fp = open_xa_file(inode, name, flags); | 
|  | 506 | if (IS_ERR(fp)) { | 
|  | 507 | err = PTR_ERR(fp); | 
|  | 508 | goto out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 509 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 510 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 511 | xinode = fp->f_dentry->d_inode; | 
|  | 512 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 513 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 514 | /* we need to copy it off.. */ | 
|  | 515 | if (xinode->i_nlink > 1) { | 
|  | 516 | fput(fp); | 
|  | 517 | err = reiserfs_xattr_del(inode, name); | 
|  | 518 | if (err < 0) | 
|  | 519 | goto out; | 
|  | 520 | /* We just killed the old one, we're not replacing anymore */ | 
|  | 521 | if (flags & XATTR_REPLACE) | 
|  | 522 | flags &= ~XATTR_REPLACE; | 
|  | 523 | goto open_file; | 
|  | 524 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 525 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 526 | /* Resize it so we're ok to write there */ | 
|  | 527 | newattrs.ia_size = buffer_size; | 
|  | 528 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 529 | mutex_lock(&xinode->i_mutex); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 530 | err = notify_change(fp->f_dentry, &newattrs); | 
|  | 531 | if (err) | 
|  | 532 | goto out_filp; | 
|  | 533 |  | 
|  | 534 | mapping = xinode->i_mapping; | 
|  | 535 | while (buffer_pos < buffer_size || buffer_pos == 0) { | 
|  | 536 | size_t chunk; | 
|  | 537 | size_t skip = 0; | 
|  | 538 | size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1)); | 
|  | 539 | if (buffer_size - buffer_pos > PAGE_CACHE_SIZE) | 
|  | 540 | chunk = PAGE_CACHE_SIZE; | 
|  | 541 | else | 
|  | 542 | chunk = buffer_size - buffer_pos; | 
|  | 543 |  | 
|  | 544 | page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); | 
|  | 545 | if (IS_ERR(page)) { | 
|  | 546 | err = PTR_ERR(page); | 
|  | 547 | goto out_filp; | 
|  | 548 | } | 
|  | 549 |  | 
|  | 550 | lock_page(page); | 
|  | 551 | data = page_address(page); | 
|  | 552 |  | 
|  | 553 | if (file_pos == 0) { | 
|  | 554 | struct reiserfs_xattr_header *rxh; | 
|  | 555 | skip = file_pos = sizeof(struct reiserfs_xattr_header); | 
|  | 556 | if (chunk + skip > PAGE_CACHE_SIZE) | 
|  | 557 | chunk = PAGE_CACHE_SIZE - skip; | 
|  | 558 | rxh = (struct reiserfs_xattr_header *)data; | 
|  | 559 | rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC); | 
|  | 560 | rxh->h_hash = cpu_to_le32(xahash); | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 | err = mapping->a_ops->prepare_write(fp, page, page_offset, | 
|  | 564 | page_offset + chunk + skip); | 
|  | 565 | if (!err) { | 
|  | 566 | if (buffer) | 
|  | 567 | memcpy(data + skip, buffer + buffer_pos, chunk); | 
|  | 568 | err = | 
|  | 569 | mapping->a_ops->commit_write(fp, page, page_offset, | 
|  | 570 | page_offset + chunk + | 
|  | 571 | skip); | 
|  | 572 | } | 
|  | 573 | unlock_page(page); | 
|  | 574 | reiserfs_put_page(page); | 
|  | 575 | buffer_pos += chunk; | 
|  | 576 | file_pos += chunk; | 
|  | 577 | skip = 0; | 
|  | 578 | if (err || buffer_size == 0 || !buffer) | 
|  | 579 | break; | 
|  | 580 | } | 
|  | 581 |  | 
|  | 582 | /* We can't mark the inode dirty if it's not hashed. This is the case | 
|  | 583 | * when we're inheriting the default ACL. If we dirty it, the inode | 
|  | 584 | * gets marked dirty, but won't (ever) make it onto the dirty list until | 
|  | 585 | * it's synced explicitly to clear I_DIRTY. This is bad. */ | 
|  | 586 | if (!hlist_unhashed(&inode->i_hash)) { | 
|  | 587 | inode->i_ctime = CURRENT_TIME_SEC; | 
|  | 588 | mark_inode_dirty(inode); | 
|  | 589 | } | 
|  | 590 |  | 
|  | 591 | out_filp: | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 592 | mutex_unlock(&xinode->i_mutex); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 593 | fput(fp); | 
|  | 594 |  | 
|  | 595 | out: | 
|  | 596 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 597 | } | 
|  | 598 |  | 
|  | 599 | /* | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 600 | * inode->i_mutex: down | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 601 | */ | 
|  | 602 | int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 603 | reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | 
|  | 604 | size_t buffer_size) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 605 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 606 | ssize_t err = 0; | 
|  | 607 | struct file *fp; | 
|  | 608 | size_t isize; | 
|  | 609 | size_t file_pos = 0; | 
|  | 610 | size_t buffer_pos = 0; | 
|  | 611 | struct page *page; | 
|  | 612 | struct inode *xinode; | 
|  | 613 | __u32 hash = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 614 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 615 | if (name == NULL) | 
|  | 616 | return -EINVAL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 617 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 618 | /* We can't have xattrs attached to v1 items since they don't have | 
|  | 619 | * generation numbers */ | 
|  | 620 | if (get_inode_sd_version(inode) == STAT_DATA_V1) | 
|  | 621 | return -EOPNOTSUPP; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 622 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 623 | fp = open_xa_file(inode, name, FL_READONLY); | 
|  | 624 | if (IS_ERR(fp)) { | 
|  | 625 | err = PTR_ERR(fp); | 
|  | 626 | goto out; | 
|  | 627 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 628 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 629 | xinode = fp->f_dentry->d_inode; | 
|  | 630 | isize = xinode->i_size; | 
|  | 631 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 632 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 633 | /* Just return the size needed */ | 
|  | 634 | if (buffer == NULL) { | 
|  | 635 | err = isize - sizeof(struct reiserfs_xattr_header); | 
|  | 636 | goto out_dput; | 
|  | 637 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 638 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 639 | if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { | 
|  | 640 | err = -ERANGE; | 
|  | 641 | goto out_dput; | 
|  | 642 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 643 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 644 | while (file_pos < isize) { | 
|  | 645 | size_t chunk; | 
|  | 646 | char *data; | 
|  | 647 | size_t skip = 0; | 
|  | 648 | if (isize - file_pos > PAGE_CACHE_SIZE) | 
|  | 649 | chunk = PAGE_CACHE_SIZE; | 
|  | 650 | else | 
|  | 651 | chunk = isize - file_pos; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 652 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 653 | page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); | 
|  | 654 | if (IS_ERR(page)) { | 
|  | 655 | err = PTR_ERR(page); | 
|  | 656 | goto out_dput; | 
|  | 657 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 658 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 659 | lock_page(page); | 
|  | 660 | data = page_address(page); | 
|  | 661 | if (file_pos == 0) { | 
|  | 662 | struct reiserfs_xattr_header *rxh = | 
|  | 663 | (struct reiserfs_xattr_header *)data; | 
|  | 664 | skip = file_pos = sizeof(struct reiserfs_xattr_header); | 
|  | 665 | chunk -= skip; | 
|  | 666 | /* Magic doesn't match up.. */ | 
|  | 667 | if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { | 
|  | 668 | unlock_page(page); | 
|  | 669 | reiserfs_put_page(page); | 
|  | 670 | reiserfs_warning(inode->i_sb, | 
|  | 671 | "Invalid magic for xattr (%s) " | 
|  | 672 | "associated with %k", name, | 
|  | 673 | INODE_PKEY(inode)); | 
|  | 674 | err = -EIO; | 
|  | 675 | goto out_dput; | 
|  | 676 | } | 
|  | 677 | hash = le32_to_cpu(rxh->h_hash); | 
|  | 678 | } | 
|  | 679 | memcpy(buffer + buffer_pos, data + skip, chunk); | 
|  | 680 | unlock_page(page); | 
|  | 681 | reiserfs_put_page(page); | 
|  | 682 | file_pos += chunk; | 
|  | 683 | buffer_pos += chunk; | 
|  | 684 | skip = 0; | 
|  | 685 | } | 
|  | 686 | err = isize - sizeof(struct reiserfs_xattr_header); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 687 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 688 | if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != | 
|  | 689 | hash) { | 
|  | 690 | reiserfs_warning(inode->i_sb, | 
|  | 691 | "Invalid hash for xattr (%s) associated " | 
|  | 692 | "with %k", name, INODE_PKEY(inode)); | 
|  | 693 | err = -EIO; | 
|  | 694 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 695 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 696 | out_dput: | 
|  | 697 | fput(fp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 698 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 699 | out: | 
|  | 700 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 701 | } | 
|  | 702 |  | 
|  | 703 | static int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 704 | __reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 705 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 706 | struct dentry *dentry; | 
|  | 707 | struct inode *dir = xadir->d_inode; | 
|  | 708 | int err = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 709 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 710 | dentry = lookup_one_len(name, xadir, namelen); | 
|  | 711 | if (IS_ERR(dentry)) { | 
|  | 712 | err = PTR_ERR(dentry); | 
|  | 713 | goto out; | 
|  | 714 | } else if (!dentry->d_inode) { | 
|  | 715 | err = -ENODATA; | 
|  | 716 | goto out_file; | 
|  | 717 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 718 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 719 | /* Skip directories.. */ | 
|  | 720 | if (S_ISDIR(dentry->d_inode->i_mode)) | 
|  | 721 | goto out_file; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 722 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 723 | if (!is_reiserfs_priv_object(dentry->d_inode)) { | 
|  | 724 | reiserfs_warning(dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have " | 
|  | 725 | "priv flag set [parent is %sset].", | 
|  | 726 | le32_to_cpu(INODE_PKEY(dentry->d_inode)-> | 
|  | 727 | k_objectid), xadir->d_name.len, | 
|  | 728 | xadir->d_name.name, namelen, name, | 
|  | 729 | is_reiserfs_priv_object(xadir-> | 
|  | 730 | d_inode) ? "" : | 
|  | 731 | "not "); | 
|  | 732 | dput(dentry); | 
|  | 733 | return -EIO; | 
|  | 734 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 735 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 736 | err = dir->i_op->unlink(dir, dentry); | 
|  | 737 | if (!err) | 
|  | 738 | d_delete(dentry); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 739 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 740 | out_file: | 
|  | 741 | dput(dentry); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 742 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 743 | out: | 
|  | 744 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 745 | } | 
|  | 746 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 747 | int reiserfs_xattr_del(struct inode *inode, const char *name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 748 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 749 | struct dentry *dir; | 
|  | 750 | int err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 751 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 752 | dir = open_xa_dir(inode, FL_READONLY); | 
|  | 753 | if (IS_ERR(dir)) { | 
|  | 754 | err = PTR_ERR(dir); | 
|  | 755 | goto out; | 
|  | 756 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 757 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 758 | err = __reiserfs_xattr_del(dir, name, strlen(name)); | 
|  | 759 | dput(dir); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 760 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 761 | if (!err) { | 
|  | 762 | inode->i_ctime = CURRENT_TIME_SEC; | 
|  | 763 | mark_inode_dirty(inode); | 
|  | 764 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 765 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 766 | out: | 
|  | 767 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 768 | } | 
|  | 769 |  | 
|  | 770 | /* The following are side effects of other operations that aren't explicitly | 
|  | 771 | * modifying extended attributes. This includes operations such as permissions | 
|  | 772 | * or ownership changes, object deletions, etc. */ | 
|  | 773 |  | 
|  | 774 | static int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 775 | reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | 
| David Howells | afefdbb | 2006-10-03 01:13:46 -0700 | [diff] [blame] | 776 | loff_t offset, u64 ino, unsigned int d_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 777 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 778 | struct dentry *xadir = (struct dentry *)buf; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 779 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 780 | return __reiserfs_xattr_del(xadir, name, namelen); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 781 |  | 
|  | 782 | } | 
|  | 783 |  | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 784 | /* This is called w/ inode->i_mutex downed */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 785 | int reiserfs_delete_xattrs(struct inode *inode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 786 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 787 | struct file *fp; | 
|  | 788 | struct dentry *dir, *root; | 
|  | 789 | int err = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 790 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 791 | /* Skip out, an xattr has no xattrs associated with it */ | 
|  | 792 | if (is_reiserfs_priv_object(inode) || | 
|  | 793 | get_inode_sd_version(inode) == STAT_DATA_V1 || | 
|  | 794 | !reiserfs_xattrs(inode->i_sb)) { | 
|  | 795 | return 0; | 
|  | 796 | } | 
|  | 797 | reiserfs_read_lock_xattrs(inode->i_sb); | 
|  | 798 | dir = open_xa_dir(inode, FL_READONLY); | 
|  | 799 | reiserfs_read_unlock_xattrs(inode->i_sb); | 
|  | 800 | if (IS_ERR(dir)) { | 
|  | 801 | err = PTR_ERR(dir); | 
|  | 802 | goto out; | 
|  | 803 | } else if (!dir->d_inode) { | 
|  | 804 | dput(dir); | 
|  | 805 | return 0; | 
|  | 806 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 807 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 808 | fp = dentry_open(dir, NULL, O_RDWR); | 
|  | 809 | if (IS_ERR(fp)) { | 
|  | 810 | err = PTR_ERR(fp); | 
|  | 811 | /* dentry_open dputs the dentry if it fails */ | 
|  | 812 | goto out; | 
|  | 813 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 814 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 815 | lock_kernel(); | 
|  | 816 | err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir); | 
|  | 817 | if (err) { | 
|  | 818 | unlock_kernel(); | 
|  | 819 | goto out_dir; | 
|  | 820 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 821 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 822 | /* Leftovers besides . and .. -- that's not good. */ | 
|  | 823 | if (dir->d_inode->i_nlink <= 2) { | 
|  | 824 | root = get_xa_root(inode->i_sb); | 
|  | 825 | reiserfs_write_lock_xattrs(inode->i_sb); | 
|  | 826 | err = vfs_rmdir(root->d_inode, dir); | 
|  | 827 | reiserfs_write_unlock_xattrs(inode->i_sb); | 
|  | 828 | dput(root); | 
|  | 829 | } else { | 
|  | 830 | reiserfs_warning(inode->i_sb, | 
|  | 831 | "Couldn't remove all entries in directory"); | 
|  | 832 | } | 
|  | 833 | unlock_kernel(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 834 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 835 | out_dir: | 
|  | 836 | fput(fp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 837 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 838 | out: | 
|  | 839 | if (!err) | 
|  | 840 | REISERFS_I(inode)->i_flags = | 
|  | 841 | REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; | 
|  | 842 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 843 | } | 
|  | 844 |  | 
|  | 845 | struct reiserfs_chown_buf { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 846 | struct inode *inode; | 
|  | 847 | struct dentry *xadir; | 
|  | 848 | struct iattr *attrs; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 849 | }; | 
|  | 850 |  | 
|  | 851 | /* XXX: If there is a better way to do this, I'd love to hear about it */ | 
|  | 852 | static int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 853 | reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, | 
| David Howells | afefdbb | 2006-10-03 01:13:46 -0700 | [diff] [blame] | 854 | loff_t offset, u64 ino, unsigned int d_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 855 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 856 | struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; | 
|  | 857 | struct dentry *xafile, *xadir = chown_buf->xadir; | 
|  | 858 | struct iattr *attrs = chown_buf->attrs; | 
|  | 859 | int err = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 860 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 861 | xafile = lookup_one_len(name, xadir, namelen); | 
|  | 862 | if (IS_ERR(xafile)) | 
|  | 863 | return PTR_ERR(xafile); | 
|  | 864 | else if (!xafile->d_inode) { | 
|  | 865 | dput(xafile); | 
|  | 866 | return -ENODATA; | 
|  | 867 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 868 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 869 | if (!S_ISDIR(xafile->d_inode->i_mode)) | 
|  | 870 | err = notify_change(xafile, attrs); | 
|  | 871 | dput(xafile); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 872 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 873 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 874 | } | 
|  | 875 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 876 | int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 877 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 878 | struct file *fp; | 
|  | 879 | struct dentry *dir; | 
|  | 880 | int err = 0; | 
|  | 881 | struct reiserfs_chown_buf buf; | 
|  | 882 | unsigned int ia_valid = attrs->ia_valid; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 883 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 884 | /* Skip out, an xattr has no xattrs associated with it */ | 
|  | 885 | if (is_reiserfs_priv_object(inode) || | 
|  | 886 | get_inode_sd_version(inode) == STAT_DATA_V1 || | 
|  | 887 | !reiserfs_xattrs(inode->i_sb)) { | 
|  | 888 | return 0; | 
|  | 889 | } | 
|  | 890 | reiserfs_read_lock_xattrs(inode->i_sb); | 
|  | 891 | dir = open_xa_dir(inode, FL_READONLY); | 
|  | 892 | reiserfs_read_unlock_xattrs(inode->i_sb); | 
|  | 893 | if (IS_ERR(dir)) { | 
|  | 894 | if (PTR_ERR(dir) != -ENODATA) | 
|  | 895 | err = PTR_ERR(dir); | 
|  | 896 | goto out; | 
|  | 897 | } else if (!dir->d_inode) { | 
|  | 898 | dput(dir); | 
|  | 899 | goto out; | 
|  | 900 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 901 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 902 | fp = dentry_open(dir, NULL, O_RDWR); | 
|  | 903 | if (IS_ERR(fp)) { | 
|  | 904 | err = PTR_ERR(fp); | 
|  | 905 | /* dentry_open dputs the dentry if it fails */ | 
|  | 906 | goto out; | 
|  | 907 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 908 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 909 | lock_kernel(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 910 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 911 | attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); | 
|  | 912 | buf.xadir = dir; | 
|  | 913 | buf.attrs = attrs; | 
|  | 914 | buf.inode = inode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 915 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 916 | err = xattr_readdir(fp, reiserfs_chown_xattrs_filler, &buf); | 
|  | 917 | if (err) { | 
|  | 918 | unlock_kernel(); | 
|  | 919 | goto out_dir; | 
|  | 920 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 921 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 922 | err = notify_change(dir, attrs); | 
|  | 923 | unlock_kernel(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 924 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 925 | out_dir: | 
|  | 926 | fput(fp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 927 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 928 | out: | 
|  | 929 | attrs->ia_valid = ia_valid; | 
|  | 930 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 931 | } | 
|  | 932 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 933 | /* Actual operations that are exported to VFS-land */ | 
|  | 934 |  | 
|  | 935 | /* | 
|  | 936 | * Inode operation getxattr() | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 937 | * Preliminary locking: we down dentry->d_inode->i_mutex | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 938 | */ | 
|  | 939 | ssize_t | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 940 | reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, | 
|  | 941 | size_t size) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 942 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 943 | struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); | 
|  | 944 | int err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 945 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 946 | if (!xah || !reiserfs_xattrs(dentry->d_sb) || | 
|  | 947 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 
|  | 948 | return -EOPNOTSUPP; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 949 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 950 | reiserfs_read_lock_xattr_i(dentry->d_inode); | 
|  | 951 | reiserfs_read_lock_xattrs(dentry->d_sb); | 
|  | 952 | err = xah->get(dentry->d_inode, name, buffer, size); | 
|  | 953 | reiserfs_read_unlock_xattrs(dentry->d_sb); | 
|  | 954 | reiserfs_read_unlock_xattr_i(dentry->d_inode); | 
|  | 955 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 956 | } | 
|  | 957 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 958 | /* | 
|  | 959 | * Inode operation setxattr() | 
|  | 960 | * | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 961 | * dentry->d_inode->i_mutex down | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 962 | */ | 
|  | 963 | int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 964 | reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 
|  | 965 | size_t size, int flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 966 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 967 | struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); | 
|  | 968 | int err; | 
|  | 969 | int lock; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 970 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 971 | if (!xah || !reiserfs_xattrs(dentry->d_sb) || | 
|  | 972 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 
|  | 973 | return -EOPNOTSUPP; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 974 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 975 | reiserfs_write_lock_xattr_i(dentry->d_inode); | 
|  | 976 | lock = !has_xattr_dir(dentry->d_inode); | 
|  | 977 | if (lock) | 
|  | 978 | reiserfs_write_lock_xattrs(dentry->d_sb); | 
|  | 979 | else | 
|  | 980 | reiserfs_read_lock_xattrs(dentry->d_sb); | 
|  | 981 | err = xah->set(dentry->d_inode, name, value, size, flags); | 
|  | 982 | if (lock) | 
|  | 983 | reiserfs_write_unlock_xattrs(dentry->d_sb); | 
|  | 984 | else | 
|  | 985 | reiserfs_read_unlock_xattrs(dentry->d_sb); | 
|  | 986 | reiserfs_write_unlock_xattr_i(dentry->d_inode); | 
|  | 987 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 988 | } | 
|  | 989 |  | 
|  | 990 | /* | 
|  | 991 | * Inode operation removexattr() | 
|  | 992 | * | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 993 | * dentry->d_inode->i_mutex down | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 994 | */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 995 | int reiserfs_removexattr(struct dentry *dentry, const char *name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 996 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 997 | int err; | 
|  | 998 | struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 999 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1000 | if (!xah || !reiserfs_xattrs(dentry->d_sb) || | 
|  | 1001 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 
|  | 1002 | return -EOPNOTSUPP; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1003 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1004 | reiserfs_write_lock_xattr_i(dentry->d_inode); | 
|  | 1005 | reiserfs_read_lock_xattrs(dentry->d_sb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1006 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1007 | /* Deletion pre-operation */ | 
|  | 1008 | if (xah->del) { | 
|  | 1009 | err = xah->del(dentry->d_inode, name); | 
|  | 1010 | if (err) | 
|  | 1011 | goto out; | 
|  | 1012 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1013 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1014 | err = reiserfs_xattr_del(dentry->d_inode, name); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1015 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1016 | dentry->d_inode->i_ctime = CURRENT_TIME_SEC; | 
|  | 1017 | mark_inode_dirty(dentry->d_inode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1018 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1019 | out: | 
|  | 1020 | reiserfs_read_unlock_xattrs(dentry->d_sb); | 
|  | 1021 | reiserfs_write_unlock_xattr_i(dentry->d_inode); | 
|  | 1022 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1023 | } | 
|  | 1024 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1025 | /* This is what filldir will use: | 
|  | 1026 | * r_pos will always contain the amount of space required for the entire | 
|  | 1027 | * list. If r_pos becomes larger than r_size, we need more space and we | 
|  | 1028 | * return an error indicating this. If r_pos is less than r_size, then we've | 
|  | 1029 | * filled the buffer successfully and we return success */ | 
|  | 1030 | struct reiserfs_listxattr_buf { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1031 | int r_pos; | 
|  | 1032 | int r_size; | 
|  | 1033 | char *r_buf; | 
|  | 1034 | struct inode *r_inode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1035 | }; | 
|  | 1036 |  | 
|  | 1037 | static int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1038 | reiserfs_listxattr_filler(void *buf, const char *name, int namelen, | 
| David Howells | afefdbb | 2006-10-03 01:13:46 -0700 | [diff] [blame] | 1039 | loff_t offset, u64 ino, unsigned int d_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1040 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1041 | struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf; | 
|  | 1042 | int len = 0; | 
|  | 1043 | if (name[0] != '.' | 
|  | 1044 | || (namelen != 1 && (name[1] != '.' || namelen != 2))) { | 
|  | 1045 | struct reiserfs_xattr_handler *xah = | 
|  | 1046 | find_xattr_handler_prefix(name); | 
|  | 1047 | if (!xah) | 
|  | 1048 | return 0;	/* Unsupported xattr name, skip it */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1049 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1050 | /* We call ->list() twice because the operation isn't required to just | 
|  | 1051 | * return the name back - we want to make sure we have enough space */ | 
|  | 1052 | len += xah->list(b->r_inode, name, namelen, NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1053 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1054 | if (len) { | 
|  | 1055 | if (b->r_pos + len + 1 <= b->r_size) { | 
|  | 1056 | char *p = b->r_buf + b->r_pos; | 
|  | 1057 | p += xah->list(b->r_inode, name, namelen, p); | 
|  | 1058 | *p++ = '\0'; | 
|  | 1059 | } | 
|  | 1060 | b->r_pos += len + 1; | 
|  | 1061 | } | 
|  | 1062 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1063 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1064 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1065 | } | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1066 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1067 | /* | 
|  | 1068 | * Inode operation listxattr() | 
|  | 1069 | * | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 1070 | * Preliminary locking: we down dentry->d_inode->i_mutex | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1071 | */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1072 | ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1073 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1074 | struct file *fp; | 
|  | 1075 | struct dentry *dir; | 
|  | 1076 | int err = 0; | 
|  | 1077 | struct reiserfs_listxattr_buf buf; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1078 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1079 | if (!dentry->d_inode) | 
|  | 1080 | return -EINVAL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1081 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1082 | if (!reiserfs_xattrs(dentry->d_sb) || | 
|  | 1083 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 
|  | 1084 | return -EOPNOTSUPP; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1085 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1086 | reiserfs_read_lock_xattr_i(dentry->d_inode); | 
|  | 1087 | reiserfs_read_lock_xattrs(dentry->d_sb); | 
|  | 1088 | dir = open_xa_dir(dentry->d_inode, FL_READONLY); | 
|  | 1089 | reiserfs_read_unlock_xattrs(dentry->d_sb); | 
|  | 1090 | if (IS_ERR(dir)) { | 
|  | 1091 | err = PTR_ERR(dir); | 
|  | 1092 | if (err == -ENODATA) | 
|  | 1093 | err = 0;	/* Not an error if there aren't any xattrs */ | 
|  | 1094 | goto out; | 
|  | 1095 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1096 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1097 | fp = dentry_open(dir, NULL, O_RDWR); | 
|  | 1098 | if (IS_ERR(fp)) { | 
|  | 1099 | err = PTR_ERR(fp); | 
|  | 1100 | /* dentry_open dputs the dentry if it fails */ | 
|  | 1101 | goto out; | 
|  | 1102 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1103 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1104 | buf.r_buf = buffer; | 
|  | 1105 | buf.r_size = buffer ? size : 0; | 
|  | 1106 | buf.r_pos = 0; | 
|  | 1107 | buf.r_inode = dentry->d_inode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1108 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1109 | REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1110 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1111 | err = xattr_readdir(fp, reiserfs_listxattr_filler, &buf); | 
|  | 1112 | if (err) | 
|  | 1113 | goto out_dir; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1114 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1115 | if (buf.r_pos > buf.r_size && buffer != NULL) | 
|  | 1116 | err = -ERANGE; | 
|  | 1117 | else | 
|  | 1118 | err = buf.r_pos; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1119 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1120 | out_dir: | 
|  | 1121 | fput(fp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1122 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1123 | out: | 
|  | 1124 | reiserfs_read_unlock_xattr_i(dentry->d_inode); | 
|  | 1125 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1126 | } | 
|  | 1127 |  | 
|  | 1128 | /* This is the implementation for the xattr plugin infrastructure */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1129 | static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1130 | static DEFINE_RWLOCK(handler_lock); | 
|  | 1131 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1132 | static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char | 
|  | 1133 | *prefix) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1134 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1135 | struct reiserfs_xattr_handler *xah = NULL; | 
|  | 1136 | struct list_head *p; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1137 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1138 | read_lock(&handler_lock); | 
|  | 1139 | list_for_each(p, &xattr_handlers) { | 
|  | 1140 | xah = list_entry(p, struct reiserfs_xattr_handler, handlers); | 
|  | 1141 | if (strncmp(xah->prefix, prefix, strlen(xah->prefix)) == 0) | 
|  | 1142 | break; | 
|  | 1143 | xah = NULL; | 
|  | 1144 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1145 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1146 | read_unlock(&handler_lock); | 
|  | 1147 | return xah; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1148 | } | 
|  | 1149 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1150 | static void __unregister_handlers(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1151 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1152 | struct reiserfs_xattr_handler *xah; | 
|  | 1153 | struct list_head *p, *tmp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1154 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1155 | list_for_each_safe(p, tmp, &xattr_handlers) { | 
|  | 1156 | xah = list_entry(p, struct reiserfs_xattr_handler, handlers); | 
|  | 1157 | if (xah->exit) | 
|  | 1158 | xah->exit(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1159 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1160 | list_del_init(p); | 
|  | 1161 | } | 
|  | 1162 | INIT_LIST_HEAD(&xattr_handlers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1163 | } | 
|  | 1164 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1165 | int __init reiserfs_xattr_register_handlers(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1166 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1167 | int err = 0; | 
|  | 1168 | struct reiserfs_xattr_handler *xah; | 
|  | 1169 | struct list_head *p; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1170 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1171 | write_lock(&handler_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1172 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1173 | /* If we're already initialized, nothing to do */ | 
|  | 1174 | if (!list_empty(&xattr_handlers)) { | 
|  | 1175 | write_unlock(&handler_lock); | 
|  | 1176 | return 0; | 
|  | 1177 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1178 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1179 | /* Add the handlers */ | 
|  | 1180 | list_add_tail(&user_handler.handlers, &xattr_handlers); | 
|  | 1181 | list_add_tail(&trusted_handler.handlers, &xattr_handlers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1182 | #ifdef CONFIG_REISERFS_FS_SECURITY | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1183 | list_add_tail(&security_handler.handlers, &xattr_handlers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1184 | #endif | 
|  | 1185 | #ifdef CONFIG_REISERFS_FS_POSIX_ACL | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1186 | list_add_tail(&posix_acl_access_handler.handlers, &xattr_handlers); | 
|  | 1187 | list_add_tail(&posix_acl_default_handler.handlers, &xattr_handlers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1188 | #endif | 
|  | 1189 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1190 | /* Run initializers, if available */ | 
|  | 1191 | list_for_each(p, &xattr_handlers) { | 
|  | 1192 | xah = list_entry(p, struct reiserfs_xattr_handler, handlers); | 
|  | 1193 | if (xah->init) { | 
|  | 1194 | err = xah->init(); | 
|  | 1195 | if (err) { | 
|  | 1196 | list_del_init(p); | 
|  | 1197 | break; | 
|  | 1198 | } | 
|  | 1199 | } | 
|  | 1200 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1201 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1202 | /* Clean up other handlers, if any failed */ | 
|  | 1203 | if (err) | 
|  | 1204 | __unregister_handlers(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1205 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1206 | write_unlock(&handler_lock); | 
|  | 1207 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1208 | } | 
|  | 1209 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1210 | void reiserfs_xattr_unregister_handlers(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1211 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1212 | write_lock(&handler_lock); | 
|  | 1213 | __unregister_handlers(); | 
|  | 1214 | write_unlock(&handler_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1215 | } | 
|  | 1216 |  | 
|  | 1217 | /* This will catch lookups from the fs root to .reiserfs_priv */ | 
|  | 1218 | static int | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1219 | xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1220 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1221 | struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root; | 
|  | 1222 | if (name->len == priv_root->d_name.len && | 
|  | 1223 | name->hash == priv_root->d_name.hash && | 
|  | 1224 | !memcmp(name->name, priv_root->d_name.name, name->len)) { | 
|  | 1225 | return -ENOENT; | 
|  | 1226 | } else if (q1->len == name->len && | 
|  | 1227 | !memcmp(q1->name, name->name, name->len)) | 
|  | 1228 | return 0; | 
|  | 1229 | return 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1230 | } | 
|  | 1231 |  | 
|  | 1232 | static struct dentry_operations xattr_lookup_poison_ops = { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1233 | .d_compare = xattr_lookup_poison, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1234 | }; | 
|  | 1235 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1236 | /* We need to take a copy of the mount flags since things like | 
|  | 1237 | * MS_RDONLY don't get set until *after* we're called. | 
|  | 1238 | * mount_flags != mount_options */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1239 | int reiserfs_xattr_init(struct super_block *s, int mount_flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1240 | { | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1241 | int err = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1242 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1243 | /* We need generation numbers to ensure that the oid mapping is correct | 
|  | 1244 | * v3.5 filesystems don't have them. */ | 
|  | 1245 | if (!old_format_only(s)) { | 
|  | 1246 | set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | 
|  | 1247 | } else if (reiserfs_xattrs_optional(s)) { | 
|  | 1248 | /* Old format filesystem, but optional xattrs have been enabled | 
|  | 1249 | * at mount time. Error out. */ | 
|  | 1250 | reiserfs_warning(s, "xattrs/ACLs not supported on pre v3.6 " | 
|  | 1251 | "format filesystem. Failing mount."); | 
|  | 1252 | err = -EOPNOTSUPP; | 
|  | 1253 | goto error; | 
|  | 1254 | } else { | 
|  | 1255 | /* Old format filesystem, but no optional xattrs have been enabled. This | 
|  | 1256 | * means we silently disable xattrs on the filesystem. */ | 
|  | 1257 | clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | 
|  | 1258 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1259 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1260 | /* If we don't have the privroot located yet - go find it */ | 
|  | 1261 | if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) { | 
|  | 1262 | struct dentry *dentry; | 
|  | 1263 | dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, | 
|  | 1264 | strlen(PRIVROOT_NAME)); | 
|  | 1265 | if (!IS_ERR(dentry)) { | 
|  | 1266 | if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { | 
|  | 1267 | struct inode *inode = dentry->d_parent->d_inode; | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 1268 | mutex_lock(&inode->i_mutex); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1269 | err = inode->i_op->mkdir(inode, dentry, 0700); | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 1270 | mutex_unlock(&inode->i_mutex); | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1271 | if (err) { | 
|  | 1272 | dput(dentry); | 
|  | 1273 | dentry = NULL; | 
|  | 1274 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1275 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1276 | if (dentry && dentry->d_inode) | 
|  | 1277 | reiserfs_warning(s, | 
|  | 1278 | "Created %s on %s - reserved for " | 
|  | 1279 | "xattr storage.", | 
|  | 1280 | PRIVROOT_NAME, | 
|  | 1281 | reiserfs_bdevname | 
|  | 1282 | (inode->i_sb)); | 
|  | 1283 | } else if (!dentry->d_inode) { | 
|  | 1284 | dput(dentry); | 
|  | 1285 | dentry = NULL; | 
|  | 1286 | } | 
|  | 1287 | } else | 
|  | 1288 | err = PTR_ERR(dentry); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1289 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1290 | if (!err && dentry) { | 
|  | 1291 | s->s_root->d_op = &xattr_lookup_poison_ops; | 
|  | 1292 | reiserfs_mark_inode_private(dentry->d_inode); | 
|  | 1293 | REISERFS_SB(s)->priv_root = dentry; | 
|  | 1294 | } else if (!(mount_flags & MS_RDONLY)) {	/* xattrs are unavailable */ | 
|  | 1295 | /* If we're read-only it just means that the dir hasn't been | 
|  | 1296 | * created. Not an error -- just no xattrs on the fs. We'll | 
|  | 1297 | * check again if we go read-write */ | 
|  | 1298 | reiserfs_warning(s, "xattrs/ACLs enabled and couldn't " | 
|  | 1299 | "find/create .reiserfs_priv. Failing mount."); | 
|  | 1300 | err = -EOPNOTSUPP; | 
|  | 1301 | } | 
|  | 1302 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1303 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1304 | error: | 
|  | 1305 | /* This is only nonzero if there was an error initializing the xattr | 
|  | 1306 | * directory or if there is a condition where we don't support them. */ | 
|  | 1307 | if (err) { | 
|  | 1308 | clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); | 
|  | 1309 | clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt)); | 
|  | 1310 | clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt)); | 
|  | 1311 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1312 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1313 | /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ | 
|  | 1314 | s->s_flags = s->s_flags & ~MS_POSIXACL; | 
|  | 1315 | if (reiserfs_posixacl(s)) | 
|  | 1316 | s->s_flags |= MS_POSIXACL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1317 |  | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1318 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1319 | } | 
|  | 1320 |  | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1321 | static int reiserfs_check_acl(struct inode *inode, int mask) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1322 | { | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1323 | struct posix_acl *acl; | 
|  | 1324 | int error = -EAGAIN; /* do regular unix permission checks by default */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1325 |  | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1326 | reiserfs_read_lock_xattr_i(inode); | 
|  | 1327 | reiserfs_read_lock_xattrs(inode->i_sb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1328 |  | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1329 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | 
|  | 1330 |  | 
|  | 1331 | reiserfs_read_unlock_xattrs(inode->i_sb); | 
|  | 1332 | reiserfs_read_unlock_xattr_i(inode); | 
|  | 1333 |  | 
|  | 1334 | if (acl) { | 
|  | 1335 | if (!IS_ERR(acl)) { | 
|  | 1336 | error = posix_acl_permission(inode, acl, mask); | 
|  | 1337 | posix_acl_release(acl); | 
|  | 1338 | } else if (PTR_ERR(acl) != -ENODATA) | 
|  | 1339 | error = PTR_ERR(acl); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1340 | } | 
|  | 1341 |  | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1342 | return error; | 
|  | 1343 | } | 
|  | 1344 |  | 
|  | 1345 | int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd) | 
|  | 1346 | { | 
|  | 1347 | /* | 
|  | 1348 | * We don't do permission checks on the internal objects. | 
|  | 1349 | * Permissions are determined by the "owning" object. | 
|  | 1350 | */ | 
| Linus Torvalds | bd4c625 | 2005-07-12 20:21:28 -0700 | [diff] [blame] | 1351 | if (is_reiserfs_priv_object(inode)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1352 | return 0; | 
|  | 1353 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1354 | /* | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1355 | * Stat data v1 doesn't support ACLs. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1356 | */ | 
| Christoph Hellwig | ec19157 | 2006-02-01 03:06:46 -0800 | [diff] [blame] | 1357 | if (get_inode_sd_version(inode) == STAT_DATA_V1) | 
|  | 1358 | return generic_permission(inode, mask, NULL); | 
|  | 1359 | else | 
|  | 1360 | return generic_permission(inode, mask, reiserfs_check_acl); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1361 | } |