| 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; | 
| Jes Sorensen | 1b1dcc1 | 2006-01-09 15:59:24 -0800 | [diff] [blame] | 427 | 	mutex_lock(&inode->i_mutex); | 
| 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 | c4cdd03 | 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, | 
 | 776 | 			      loff_t offset, ino_t 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, | 
 | 854 | 			     loff_t offset, ino_t 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, | 
 | 1039 | 			  loff_t offset, ino_t 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 | } |