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