1 diff -rupN --exclude='ide*' linux-2.4.20.orig/fs/Config.in linux-2.4.20/fs/Config.in
2 --- linux-2.4.20.orig/fs/Config.in 2002-11-29 01:53:15.000000000 +0200
3 +++ linux-2.4.20/fs/Config.in 2004-02-08 21:37:47.000000000 +0200
4 @@ -48,6 +48,9 @@ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFI
6 tristate 'Compressed ROM file system support' CONFIG_CRAMFS
7 bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
8 +if [ "$CONFIG_TMPFS" = "y" ]; then
9 + bool ' tmpfs Extended Attributes' CONFIG_TMPFS_XATTR
11 define_bool CONFIG_RAMFS y
13 tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
14 diff -rupN --exclude='ide*' linux-2.4.20.orig/include/linux/shmem_fs.h linux-2.4.20/include/linux/shmem_fs.h
15 --- linux-2.4.20.orig/include/linux/shmem_fs.h 2001-12-21 19:42:03.000000000 +0200
16 +++ linux-2.4.20/include/linux/shmem_fs.h 2004-02-08 21:40:34.000000000 +0200
19 /* inode in-kernel data */
21 +#include <linux/config.h>
23 #define SHMEM_NR_DIRECT 16
26 @@ -28,6 +30,10 @@ struct shmem_inode_info {
27 unsigned long swapped;
28 int locked; /* into memory */
29 struct list_head list;
30 +#ifdef CONFIG_TMPFS_XATTR
31 + struct list_head xattrs;
32 + struct list_head *xtail;
37 @@ -39,6 +45,15 @@ struct shmem_sb_info {
41 +#ifdef CONFIG_TMPFS_XATTR
46 + struct list_head list;
50 #define SHMEM_I(inode) (&inode->u.shmem_i)
53 diff -rupN --exclude='ide*' linux-2.4.20.orig/mm/shmem.c linux-2.4.20/mm/shmem.c
54 --- linux-2.4.20.orig/mm/shmem.c 2002-11-29 01:53:15.000000000 +0200
55 +++ linux-2.4.20/mm/shmem.c 2004-02-09 11:41:45.000000000 +0200
57 #include <linux/string.h>
58 #include <linux/locks.h>
59 #include <linux/smp_lock.h>
60 +#include <linux/slab.h>
61 +#include <linux/xattr.h>
63 #include <asm/uaccess.h>
65 @@ -58,6 +60,344 @@ atomic_t shmem_nrpages = ATOMIC_INIT(0);
67 static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long);
70 +static struct inode_operations shmem_symlink_inode_operations;
71 +static struct inode_operations shmem_symlink_inline_operations;
74 +#ifdef CONFIG_TMPFS_XATTR
75 +#define xattr_name(xattr) \
76 + ((char *)xattr->entity)
78 +#define xattr_value(xattr) \
79 + ((void *)xattr->entity + xattr->namelen + 1)
81 +/* allocates memory for new xattr with name length of @namelen and value size of
83 +static struct shmem_xattr *
84 +shmem_xattr_alloc(u8 namelen, u16 valuelen)
87 + struct shmem_xattr *xattr;
89 + size = namelen + 1 + valuelen;
91 + if (!(xattr = kmalloc(sizeof(*xattr), GFP_KERNEL)))
94 + if (!(xattr->entity = kmalloc(size, GFP_KERNEL))) {
99 + xattr->namelen = namelen;
100 + xattr->valuelen = valuelen;
104 +/* reallocs passed @xattr with new @value. */
106 +shmem_xattr_realloc(struct shmem_xattr *xattr, u16 valuelen)
108 + if (xattr->valuelen != valuelen) {
112 + /* allocating new entity. */
113 + new_size = xattr->namelen + 1 + valuelen;
115 + if (!(entity = kmalloc(new_size, GFP_KERNEL)))
118 + /* copying old name to new entity.*/
119 + memcpy(entity, xattr->entity, xattr->namelen);
120 + *((char *)(entity + xattr->namelen)) = '\0';
122 + /* finishing the change.*/
123 + kfree(xattr->entity);
124 + xattr->entity = entity;
125 + xattr->valuelen = valuelen;
131 +/* assigns @name and @value to passed @xattr. */
133 +shmem_xattr_assign(struct shmem_xattr *xattr,
134 + const char *name, void *value)
137 + if (xattr->namelen != strlen(name))
140 + memcpy(xattr->entity, name, xattr->namelen);
141 + *((char *)(xattr->entity + xattr->namelen)) = '\0';
145 + memcpy(xattr_value(xattr),
146 + value, xattr->valuelen);
152 +/* frees passed @xattr. */
154 +shmem_xattr_free(struct shmem_xattr *xattr)
156 + kfree(xattr->entity);
160 +/* lookups passed @name inside @inode's xattr list. */
161 +struct shmem_xattr *
162 +shmem_xattr_find(struct inode *inode, const char *name)
165 + struct list_head *p;
166 + struct shmem_xattr *xattr;
167 + struct shmem_inode_info *info;
169 + info = SHMEM_I(inode);
170 + namelen = strlen(name);
172 + list_for_each(p, &info->xattrs) {
173 + xattr = list_entry(p, struct shmem_xattr, list);
175 + if (xattr->namelen == namelen &&
176 + !memcmp(xattr->entity, name, namelen))
185 +/* allocates new xattr and fills it with passed value, name, etc. */
187 +shmem_xattr_set(struct inode *inode, const char *name,
188 + void *value, u16 valuelen, int flags)
191 + struct shmem_xattr *xattr;
192 + struct shmem_inode_info *info;
194 + xattr = shmem_xattr_find(inode, name);
197 + if (flags & XATTR_CREATE)
200 + if ((error = shmem_xattr_realloc(xattr, valuelen)))
203 + if ((error = shmem_xattr_assign(xattr, NULL, value)))
206 + info = SHMEM_I(inode);
208 + if (flags & XATTR_REPLACE)
211 + if (!(xattr = shmem_xattr_alloc(strlen(name), valuelen)))
214 + if ((error = shmem_xattr_assign(xattr, name, value)))
217 + list_add(&xattr->list, info->xtail);
218 + info->xtail = &xattr->list;
224 +/* fills passed @value by attribute value found by @name. */
226 +shmem_xattr_get(struct inode *inode, const char *name,
227 + void *value, size_t valuelen)
229 + struct shmem_xattr *xattr;
231 + if (!(xattr = shmem_xattr_find(inode, name)))
234 + /* handling value size guess request */
235 + if (valuelen == 0 || value == NULL)
236 + return xattr->valuelen;
238 + if (xattr->valuelen > valuelen)
241 + memcpy(value, xattr_value(xattr),
244 + return xattr->valuelen;
247 +/* deletes passed @xattr from inode xattr list and frees it. */
249 +shmem_xattr_delete(struct inode *inode, struct shmem_xattr *xattr)
251 + struct shmem_inode_info *info;
253 + info = SHMEM_I(inode);
255 + if (&xattr->list == info->xtail)
256 + info->xtail = xattr->list.prev;
258 + list_del(&xattr->list);
259 + shmem_xattr_free(xattr);
264 +/* removes attribute found by passed @name. */
266 +shmem_xattr_remove(struct inode *inode, const char *name)
268 + struct shmem_xattr *xattr;
270 + if (!(xattr = shmem_xattr_find(inode, name)))
273 + return shmem_xattr_delete(inode, xattr);
277 +shmem_xattr_can_read(struct inode *inode, const char *name)
279 + /* check for inlined symlinks. They store path inside inode info and
280 + * thus, cannot be used for access xattrs. */
281 + if (S_ISLNK(inode->i_mode) &&
282 + inode->i_op == &shmem_symlink_inline_operations)
287 + return permission(inode, MAY_READ);
291 +shmem_xattr_can_write(struct inode *inode, const char *name)
293 + if (IS_RDONLY(inode))
296 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode) ||
297 + S_ISLNK(inode->i_mode))
302 + if ((!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) ||
303 + inode->i_mode & S_ISVTX)
308 + return permission(inode, MAY_WRITE);
311 +/* fills passed @value with data of attribute @name from @dentry->d_inode
312 + * attribute list. */
314 +shmem_getxattr(struct dentry *dentry, const char *name,
315 + void *value, size_t valuelen)
318 + struct inode *inode = dentry->d_inode;
323 + if ((error = shmem_xattr_can_read(inode, name)))
326 + return shmem_xattr_get(inode, name,
331 +/* updates attribute with @name inside @dentry->d_inode attributes list (if
332 + * any), or creates new attribute with name @name and value @value and put it to
333 + * inode attributes list.*/
335 +shmem_setxattr(struct dentry *dentry, const char *name,
336 + void *value, size_t valuelen, int flags)
339 + struct inode *inode = dentry->d_inode;
344 + if ((error = shmem_xattr_can_write(inode, name)))
347 + if (value == NULL) {
352 + return shmem_xattr_set(inode, name, value,
356 +/* removes attribute with passed @name from @dentry->d_inode attributes list. */
358 +shmem_removexattr(struct dentry *dentry, const char *name)
361 + struct inode *inode = dentry->d_inode;
366 + if ((error = shmem_xattr_can_write(inode, name)))
369 + return shmem_xattr_remove(inode, name);
372 +/* fills passed @data with list of @dentry->d_inode attributes. Returns size of
373 + * actuall data put to @data. */
375 +shmem_listxattr(struct dentry *dentry, char *data, size_t buf_size)
378 + struct list_head *p;
379 + struct shmem_xattr *xattr;
380 + struct shmem_inode_info *info;
381 + struct inode *inode = dentry->d_inode;
383 + info = SHMEM_I(inode);
385 + list_for_each(p, &info->xattrs) {
386 + xattr = list_entry(p, struct shmem_xattr, list);
387 + size += xattr->namelen + 1;
390 + /* handling data size guess request. */
391 + if (buf_size == 0 || data == NULL)
394 + if (size > buf_size)
397 + list_for_each(p, &info->xattrs) {
398 + xattr = list_entry(p, struct shmem_xattr, list);
399 + memcpy(data, xattr->entity, xattr->namelen + 1);
400 + data += xattr->namelen + 1;
408 * shmem_recalc_inode - recalculate the size of an inode
410 @@ -359,6 +699,11 @@ static void shmem_truncate (struct inode
412 static void shmem_delete_inode(struct inode * inode)
414 +#ifdef CONFIG_TMPFS_XATTR
415 + struct list_head *tmp, *p;
416 + struct shmem_xattr *xattr;
417 + struct shmem_inode_info * info = SHMEM_I(inode);
419 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
421 if (inode->i_op->truncate == shmem_truncate) {
422 @@ -371,6 +716,12 @@ static void shmem_delete_inode(struct in
423 spin_lock (&sbinfo->stat_lock);
424 sbinfo->free_inodes++;
425 spin_unlock (&sbinfo->stat_lock);
426 +#ifdef CONFIG_TMPFS_XATTR
427 + list_for_each_safe(p, tmp, &info->xattrs) {
428 + xattr = list_entry(p, struct shmem_xattr, list);
429 + shmem_xattr_delete(inode, xattr);
435 @@ -727,6 +1078,11 @@ struct inode *shmem_get_inode(struct sup
437 spin_lock_init (&info->lock);
438 sema_init (&info->sem, 1);
440 +#ifdef CONFIG_TMPFS_XATTR
441 + INIT_LIST_HEAD(&info->xattrs);
442 + info->xtail = &info->xattrs;
444 switch (mode & S_IFMT) {
446 init_special_inode(inode, mode, dev);
447 @@ -777,10 +1133,6 @@ out:
452 -static struct inode_operations shmem_symlink_inode_operations;
453 -static struct inode_operations shmem_symlink_inline_operations;
456 shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
458 @@ -1250,6 +1602,12 @@ static struct inode_operations shmem_sym
459 truncate: shmem_truncate,
460 readlink: shmem_readlink,
461 follow_link: shmem_follow_link,
462 +#ifdef CONFIG_TMPFS_XATTR
463 + setxattr: shmem_setxattr,
464 + getxattr: shmem_getxattr,
465 + listxattr: shmem_listxattr,
466 + removexattr: shmem_removexattr,
470 static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long * blocks, unsigned long *inodes)
471 @@ -1398,6 +1756,12 @@ static struct file_operations shmem_file
473 static struct inode_operations shmem_inode_operations = {
474 truncate: shmem_truncate,
475 +#ifdef CONFIG_TMPFS_XATTR
476 + setxattr: shmem_setxattr,
477 + getxattr: shmem_getxattr,
478 + listxattr: shmem_listxattr,
479 + removexattr: shmem_removexattr,
483 static struct inode_operations shmem_dir_inode_operations = {
484 @@ -1411,6 +1775,12 @@ static struct inode_operations shmem_dir
487 rename: shmem_rename,
488 +#ifdef CONFIG_TMPFS_XATTR
489 + setxattr: shmem_setxattr,
490 + getxattr: shmem_getxattr,
491 + listxattr: shmem_listxattr,
492 + removexattr: shmem_removexattr,