diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 7a35a6e..fe54552 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -356,3 +356,6 @@
 347	i386	process_vm_readv	sys_process_vm_readv		compat_sys_process_vm_readv
 348	i386	process_vm_writev	sys_process_vm_writev		compat_sys_process_vm_writev
 349	i386	kcmp			sys_kcmp
+350	i386	xstat			sys_xstat
+351	i386	fxstat			sys_fxstat
+352	i386	xgetdents		sys_xgetdents
\ No newline at end of file
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index 51171ae..f17413b 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -319,6 +319,9 @@
 310	64	process_vm_readv	sys_process_vm_readv
 311	64	process_vm_writev	sys_process_vm_writev
 312	64	kcmp			sys_kcmp
+313	common	xstat			sys_xstat
+314	common	fxstat			sys_fxstat
+315	common	xgetdents		sys_xgetdents
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c3411d4..f1d24b3 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1987,6 +1987,8 @@ extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
 				struct kstat *stat);
 extern void ext4_evict_inode(struct inode *);
 extern void ext4_clear_inode(struct inode *);
+extern int ext4_file_getattr(struct vfsmount *mnt, struct dentry *dentry,
+			     struct kstat *stat);
 extern int  ext4_sync_inode(handle_t *, struct inode *);
 extern void ext4_dirty_inode(struct inode *, int);
 extern int ext4_change_inode_journal_flag(struct inode *, int);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 3b0e3bd..9992273 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -325,7 +325,7 @@ const struct file_operations ext4_file_operations = {
 
 const struct inode_operations ext4_file_inode_operations = {
 	.setattr	= ext4_setattr,
-	.getattr	= ext4_getattr,
+	.getattr	= ext4_file_getattr,
 #ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 6324f74..2c5a427 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4377,11 +4377,37 @@ err_out:
 int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		 struct kstat *stat)
 {
-	struct inode *inode;
-	unsigned long delalloc_blocks;
+	struct inode *inode = dentry->d_inode;
+	struct ext4_inode_info *ei = EXT4_I(inode);
+
+	stat->result_mask |= XSTAT_BTIME;
+	stat->btime.tv_sec = ei->i_crtime.tv_sec;
+	stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
+
+	if (inode->i_ino != EXT4_ROOT_INO) {
+		stat->result_mask |= XSTAT_GEN;
+		stat->gen = inode->i_generation;
+	}
+	if (S_ISDIR(inode->i_mode) || IS_I_VERSION(inode)) {
+		stat->result_mask |= XSTAT_VERSION;
+		stat->version = inode->i_version;
+	}
+
+	ext4_get_inode_flags(ei);
+	stat->ioc_flags |= ei->i_flags & EXT4_FL_USER_VISIBLE;
+	stat->result_mask |= XSTAT_IOC_FLAGS;
 
-	inode = dentry->d_inode;
 	generic_fillattr(inode, stat);
+	return 0;
+}
+
+int ext4_file_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		      struct kstat *stat)
+{
+	struct inode *inode = dentry->d_inode;
+	u64 delalloc_blocks;
+
+	ext4_getattr(mnt, dentry, stat);
 
 	/*
 	 * We can't update i_blocks if the block allocation is delayed
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2a42cc0..dad9f7e 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2976,6 +2976,7 @@ const struct inode_operations ext4_dir_inode_operations = {
 	.mknod		= ext4_mknod,
 	.rename		= ext4_rename,
 	.setattr	= ext4_setattr,
+	.getattr        = ext4_getattr,
 #ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
@@ -2988,6 +2989,7 @@ const struct inode_operations ext4_dir_inode_operations = {
 
 const struct inode_operations ext4_special_inode_operations = {
 	.setattr	= ext4_setattr,
+	.getattr        = ext4_getattr,
 #ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..64ee59c 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3285,6 +3285,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	if (sb->s_magic != EXT4_SUPER_MAGIC)
 		goto cantfind_ext4;
 	sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
+	memcpy(sb->s_volume_id, es->s_uuid, sizeof(sb->s_volume_id));
 
 	/* Warn if metadata_csum and gdt_csum are both set. */
 	if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index ed9354a..7c5184a 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -35,6 +35,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
 	.follow_link	= page_follow_link_light,
 	.put_link	= page_put_link,
 	.setattr	= ext4_setattr,
+	.getattr        = ext4_getattr,
 #ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
@@ -47,6 +48,7 @@ const struct inode_operations ext4_fast_symlink_inode_operations = {
 	.readlink	= generic_readlink,
 	.follow_link	= ext4_follow_link,
 	.setattr	= ext4_setattr,
+	.getattr        = ext4_getattr,
 #ifdef CONFIG_EXT4_FS_XATTR
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 259b088..05dc7af 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1196,7 +1196,8 @@ static int compare_dents(const void *a, const void *b)
  * @dip: The GFS2 inode
  * @offset: The offset in the file to read from
  * @opaque: opaque data to pass to filldir
- * @filldir: The function to pass entries to
+ * @filldir: The function to pass entries to. Could be filldir_t or xfilldir_t
+ * @stat: Pointer to a kstat buffer. filldir = kstat ? xfilldir_t : filldir_t
  * @darr: an array of struct gfs2_dirent pointers to read
  * @entries: the number of entries in darr
  * @copied: pointer to int that's non-zero if a entry has been copied out
@@ -1210,7 +1211,7 @@ static int compare_dents(const void *a, const void *b)
  */
 
 static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
-			   void *opaque, filldir_t filldir,
+			   void *opaque, void *filldir, struct kstat *stat,
 			   const struct gfs2_dirent **darr, u32 entries,
 			   int *copied)
 {
@@ -1251,10 +1252,33 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
 			*offset = off;
 		}
 
-		error = filldir(opaque, (const char *)(dent + 1),
-				be16_to_cpu(dent->de_name_len),
-				off, be64_to_cpu(dent->de_inum.no_addr),
-				be16_to_cpu(dent->de_type));
+		if (!stat) {
+			filldir_t fdir = (filldir_t) filldir;
+			error = fdir(opaque, (const char *)(dent + 1),
+				     be16_to_cpu(dent->de_name_len),
+				     off, be64_to_cpu(dent->de_inum.no_addr),
+				     be16_to_cpu(dent->de_type));
+		} else { /* xfilldir */
+			xfilldir_t fdir = (xfilldir_t) filldir;
+			struct inode *inode;
+			inode = gfs2_inode_lookup(dip->i_inode.i_sb,
+						  be16_to_cpu(dent->de_type),
+						  be64_to_cpu(dent->de_inum.no_addr),
+						  be64_to_cpu(dent->de_inum.no_formal_ino), 0);
+			if (IS_ERR(inode))
+				return 1;
+
+			error = gfs2_getattr_i(inode, stat);
+			if (error)
+				goto iput;
+
+			error = fdir(opaque, (const char *)(dent + 1),
+				     be16_to_cpu(dent->de_name_len),
+				     off, be64_to_cpu(dent->de_inum.no_addr),
+				     be16_to_cpu(dent->de_type), stat);
+		iput:
+			iput(inode);
+		}
 		if (error)
 			return 1;
 
@@ -1290,8 +1314,8 @@ static void gfs2_free_sort_buffer(void *ptr)
 }
 
 static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
-			      filldir_t filldir, int *copied, unsigned *depth,
-			      u64 leaf_no)
+			      void *filldir, struct kstat *stat, int *copied, 
+			      unsigned *depth, u64 leaf_no)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -1368,7 +1392,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
 	} while(lfn);
 
 	BUG_ON(entries2 != entries);
-	error = do_filldir_main(ip, offset, opaque, filldir, darr,
+	error = do_filldir_main(ip, offset, opaque, filldir, stat, darr,
 				entries, copied);
 out_free:
 	for(i = 0; i < leaf; i++)
@@ -1436,7 +1460,7 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
  */
 
 static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
-		      filldir_t filldir, struct file_ra_state *f_ra)
+		      void *filldir, struct kstat *stat, struct file_ra_state *f_ra)
 {
 	struct gfs2_inode *dip = GFS2_I(inode);
 	u32 hsize, len = 0;
@@ -1460,7 +1484,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
 
 	while (index < hsize) {
 		error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
-					   &copied, &depth,
+					   stat, &copied, &depth,
 					   be64_to_cpu(lp[index]));
 		if (error)
 			break;
@@ -1475,7 +1499,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
 }
 
 int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
-		  filldir_t filldir, struct file_ra_state *f_ra)
+		  void *filldir, struct kstat *stat, struct file_ra_state *f_ra)
 {
 	struct gfs2_inode *dip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -1489,7 +1513,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
 		return 0;
 
 	if (dip->i_diskflags & GFS2_DIF_EXHASH)
-		return dir_e_read(inode, offset, opaque, filldir, f_ra);
+		return dir_e_read(inode, offset, opaque, filldir, stat, f_ra);
 
 	if (!gfs2_is_stuffed(dip)) {
 		gfs2_consist_inode(dip);
@@ -1521,8 +1545,8 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
 			error = -EIO;
 			goto out;
 		}
-		error = do_filldir_main(dip, offset, opaque, filldir, darr,
-					dip->i_entries, &copied);
+		error = do_filldir_main(dip, offset, opaque, filldir, stat,
+					darr, dip->i_entries, &copied);
 out:
 		kfree(darr);
 	}
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
index 98c960b..8846757 100644
--- a/fs/gfs2/dir.h
+++ b/fs/gfs2/dir.h
@@ -25,7 +25,7 @@ extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
 			const struct gfs2_inode *ip);
 extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry);
 extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
-			 filldir_t filldir, struct file_ra_state *f_ra);
+			 void *filldir, struct kstat *stat, struct file_ra_state *f_ra);
 extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
 			  const struct gfs2_inode *nip, unsigned int new_type);
 
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c
index e8ed6d4..f0bba59 100644
--- a/fs/gfs2/export.c
+++ b/fs/gfs2/export.c
@@ -112,7 +112,7 @@ static int gfs2_get_name(struct dentry *parent, char *name,
 	if (error)
 		return error;
 
-	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir, &f_ra);
+	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir, NULL, &f_ra);
 
 	gfs2_glock_dq_uninit(&gh);
 
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 30e2199..fb83218 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -25,6 +25,7 @@
 #include <asm/uaccess.h>
 #include <linux/dlm.h>
 #include <linux/dlm_plock.h>
+#include <linux/stat.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -88,7 +89,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
  *
  * Returns: errno
  */
-
 static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
 	struct inode *dir = file->f_mapping->host;
@@ -104,7 +104,51 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
 		return error;
 	}
 
-	error = gfs2_dir_read(dir, &offset, dirent, filldir, &file->f_ra);
+	error = gfs2_dir_read(dir, &offset, dirent, (void *) filldir, NULL,
+			      &file->f_ra);
+
+	gfs2_glock_dq_uninit(&d_gh);
+
+	file->f_pos = offset;
+
+	return error;
+}
+
+/**
+ * gfs2_xreaddir - Read directory entries with xstat info
+ * @file: The directory to read from
+ * @xdirent: Buffer for xdirents
+ * @xfilldir: Function used to do the copying
+ *
+ * Returns: errno
+ */
+static int gfs2_xreaddir(struct file *file, void *xdirent, xfilldir_t xfilldir,
+			 unsigned flags, unsigned int mask)
+{
+	struct inode *dir = file->f_mapping->host;
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct gfs2_holder d_gh;
+	struct kstat stat;
+	u64 offset = file->f_pos;
+	int error;
+
+	error = xdirent_get_params(mask, &stat);
+	if (error != 0)
+		return error;
+
+       	stat.query_flags = flags & KSTAT_QUERY_FLAGS;
+        stat.result_mask = 0;
+	stat.information = 0;
+        stat.ioc_flags = 0;
+
+	gfs2_holder_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+	error = gfs2_glock_nq(&d_gh);
+	if (error) {
+		gfs2_holder_uninit(&d_gh);
+		return error;
+	}
+
+	error = gfs2_dir_read(dir, &offset, xdirent, (void *) xfilldir, &stat, &file->f_ra);
 
 	gfs2_glock_dq_uninit(&d_gh);
 
@@ -1043,6 +1087,7 @@ const struct file_operations gfs2_file_fops = {
 
 const struct file_operations gfs2_dir_fops = {
 	.readdir	= gfs2_readdir,
+	.xreaddir       = gfs2_xreaddir,
 	.unlocked_ioctl	= gfs2_ioctl,
 	.open		= gfs2_open,
 	.release	= gfs2_release,
@@ -1073,6 +1118,7 @@ const struct file_operations gfs2_file_fops_nolock = {
 
 const struct file_operations gfs2_dir_fops_nolock = {
 	.readdir	= gfs2_readdir,
+	.xreaddir       = gfs2_xreaddir,
 	.unlocked_ioctl	= gfs2_ioctl,
 	.open		= gfs2_open,
 	.release	= gfs2_release,
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index f2709ea..7d18fda 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1670,6 +1670,15 @@ out:
 	return error;
 }
 
+inline int gfs2_getattr_i(struct inode *inode, struct kstat *stat)
+{
+	int error = 0;
+
+	generic_fillattr(inode, stat);
+
+	return error;
+}
+
 /**
  * gfs2_getattr - Read out an inode's attributes
  * @mnt: The vfsmount the inode is being accessed from
@@ -1701,7 +1710,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		unlock = 1;
 	}
 
-	generic_fillattr(inode, stat);
+	gfs2_getattr_i(inode, stat);
 	if (unlock)
 		gfs2_glock_dq_uninit(&gh);
 
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index c53c747..79775fa 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -106,6 +106,8 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip);
 extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
 				  int is_root);
 extern int gfs2_permission(struct inode *inode, int mask);
+extern int gfs2_getattr_i(struct inode *inode, struct kstat *stat);
+
 extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
 extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
 extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
diff --git a/fs/readdir.c b/fs/readdir.c
index 39e3370..dd53207 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -20,11 +20,12 @@
 
 #include <asm/uaccess.h>
 
-int vfs_readdir(struct file *file, filldir_t filler, void *buf)
+static int vfs_xreaddir_i(struct file *file, filldir_t filler, xfilldir_t xfiller,
+			  void *buf, unsigned flags, unsigned int mask)
 {
 	struct inode *inode = file->f_path.dentry->d_inode;
 	int res = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
+	if (!file->f_op || (filler ? !file->f_op->readdir : !file->f_op->xreaddir))
 		goto out;
 
 	res = security_file_permission(file, MAY_READ);
@@ -37,7 +38,8 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
 
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
-		res = file->f_op->readdir(file, buf, filler);
+		res = filler ? file->f_op->readdir(file, buf, filler) :
+			file->f_op->xreaddir(file, buf, xfiller, flags, mask);
 		file_accessed(file);
 	}
 	mutex_unlock(&inode->i_mutex);
@@ -45,8 +47,20 @@ out:
 	return res;
 }
 
+int vfs_readdir(struct file *file, filldir_t filler, void *buf)
+{
+	return vfs_xreaddir_i(file, filler, NULL, buf, 0, 0);
+}
+
 EXPORT_SYMBOL(vfs_readdir);
 
+int vfs_xreaddir(struct file *file, xfilldir_t xfiller, void *buf, unsigned flags,
+		 unsigned int mask)
+{
+	return vfs_xreaddir_i(file, NULL, xfiller, buf, flags, mask);
+}
+EXPORT_SYMBOL(vfs_xreaddir);
+
 /*
  * Traditional linux readdir() handling..
  *
@@ -127,17 +141,6 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
 
 #endif /* __ARCH_WANT_OLD_READDIR */
 
-/*
- * New, all-improved, singing, dancing, iBCS2-compliant getdents()
- * interface. 
- */
-struct linux_dirent {
-	unsigned long	d_ino;
-	unsigned long	d_off;
-	unsigned short	d_reclen;
-	char		d_name[1];
-};
-
 struct getdents_callback {
 	struct linux_dirent __user * current_dir;
 	struct linux_dirent __user * previous;
@@ -145,17 +148,18 @@ struct getdents_callback {
 	int error;
 };
 
-static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
-		   u64 ino, unsigned int d_type)
+static int xfilldir_i(void *__buf, const char *name, int namlen, loff_t offset,
+		      u64 ino, unsigned int d_type, struct kstat *stat)
 {
-	struct linux_dirent __user * dirent;
-	struct getdents_callback * buf = (struct getdents_callback *) __buf;
+	struct linux_dirent __user *dirent;
+	struct getdents_callback *buf = (struct getdents_callback *) __buf;
 	unsigned long d_ino;
+	int stat_sz = stat ? sizeof(struct xstat) : 0;
 	int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
-		sizeof(long));
+			   sizeof(long));
 
-	buf->error = -EINVAL;	/* only used if we fail.. */
-	if (reclen > buf->count)
+	buf->error = -EINVAL; /* only used if we fail */
+	if (reclen + stat_sz > buf->count)
 		return -EINVAL;
 	d_ino = ino;
 	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
@@ -178,38 +182,63 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
 		goto efault;
 	if (__put_user(d_type, (char __user *) dirent + reclen - 1))
 		goto efault;
+
 	buf->previous = dirent;
-	dirent = (void __user *)dirent + reclen;
+
+	if (stat) {
+		/* Copy the kstat struct here */
+		struct linux_xdirent __user *xdirent;
+		xdirent = container_of(dirent, struct linux_xdirent, x_dent);
+		if (xstat_set_result(stat, &xdirent->x_st))
+			goto efault;
+		xdirent = (void __user *)xdirent + reclen + stat_sz;
+		dirent = &xdirent->x_dent;
+	} else {
+		dirent = (void __user *)dirent + reclen;
+	}
+	
 	buf->current_dir = dirent;
-	buf->count -= reclen;
+	buf->count -= reclen + stat_sz;
+
 	return 0;
 efault:
 	buf->error = -EFAULT;
 	return -EFAULT;
 }
 
-SYSCALL_DEFINE3(getdents, unsigned int, fd,
-		struct linux_dirent __user *, dirent, unsigned int, count)
+static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
+		   u64 ino, unsigned int d_type)
 {
-	struct file * file;
-	struct linux_dirent __user * lastdirent;
+	return xfilldir_i(__buf, name, namlen, offset, ino, d_type, NULL);
+}
+
+static int xfilldir(void *__buf, const char *name, int namlen, loff_t offset,
+		    u64 ino, unsigned int d_type, struct kstat *stat)
+{
+	return xfilldir_i(__buf, name, namlen, offset, ino, d_type, stat);
+}
+
+static int xgetdents_i(unsigned int fd, struct linux_dirent __user *dirent,
+		       struct linux_xdirent __user *xdirent, unsigned int count,
+		       unsigned int flags, unsigned int mask)
+{
+	struct file *file;
 	struct getdents_callback buf;
+	struct linux_dirent __user *lastdirent;
 	int fput_needed;
 	int error;
-
-	if (!access_ok(VERIFY_WRITE, dirent, count))
-		return -EFAULT;
-
+	
 	file = fget_light(fd, &fput_needed);
 	if (!file)
 		return -EBADF;
 
-	buf.current_dir = dirent;
+	buf.current_dir = dirent ? dirent : &xdirent->x_dent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
-	error = vfs_readdir(file, filldir, &buf);
+	error = dirent ? vfs_readdir(file, filldir, &buf) : 
+		vfs_xreaddir(file, xfilldir, &buf, flags, mask);
 	if (error >= 0)
 		error = buf.error;
 	lastdirent = buf.previous;
@@ -223,6 +252,25 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
 	return error;
 }
 
+SYSCALL_DEFINE3(getdents, unsigned int, fd,
+		struct linux_dirent __user *, dirent, unsigned int, count)
+{
+	if (!access_ok(VERIFY_WRITE, dirent, count))
+		return -EFAULT;
+
+	return xgetdents_i(fd, dirent, NULL, count, 0, 0);
+}
+
+SYSCALL_DEFINE5(xgetdents, unsigned int, fd,
+		struct linux_xdirent __user *, xdirent, unsigned int, count,
+		unsigned, flags, unsigned int, mask)
+{
+	if (!access_ok(VERIFY_WRITE, xdirent, count))
+		return -EFAULT;
+
+	return xgetdents_i(fd, NULL, xdirent, count, flags, mask);
+}
+
 struct getdents_callback64 {
 	struct linux_dirent64 __user * current_dir;
 	struct linux_dirent64 __user * previous;
diff --git a/fs/stat.c b/fs/stat.c
index b6ff118..db38c89 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -18,8 +18,20 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
+/**
+ * generic_fillattr - Fill in the basic attributes from the inode struct
+ * @inode: Inode to use as the source
+ * @stat: Where to fill in the attributes
+ *
+ * Fill in the basic attributes in the kstat structure from data that's to be
+ * found on the VFS inode structure.  This is the default if no getattr inode
+ * operation is supplied.
+ */
 void generic_fillattr(struct inode *inode, struct kstat *stat)
 {
+	struct super_block *sb = inode->i_sb;
+	u32 x;
+
 	stat->dev = inode->i_sb->s_dev;
 	stat->ino = inode->i_ino;
 	stat->mode = inode->i_mode;
@@ -27,17 +39,61 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
 	stat->uid = inode->i_uid;
 	stat->gid = inode->i_gid;
 	stat->rdev = inode->i_rdev;
-	stat->size = i_size_read(inode);
-	stat->atime = inode->i_atime;
 	stat->mtime = inode->i_mtime;
 	stat->ctime = inode->i_ctime;
-	stat->blksize = (1 << inode->i_blkbits);
+	stat->size = i_size_read(inode);
 	stat->blocks = inode->i_blocks;
-}
+	stat->blksize = (1 << inode->i_blkbits);
 
+	stat->result_mask |= XSTAT_BASIC_STATS & ~XSTAT_RDEV;
+	if (IS_NOATIME(inode))
+		stat->result_mask &= ~XSTAT_ATIME;
+	else
+		stat->atime = inode->i_atime;
+
+	if (S_ISREG(stat->mode) && stat->nlink == 0)
+		stat->information |= XSTAT_INFO_TEMPORARY;
+	if (IS_AUTOMOUNT(inode))
+		stat->information |= XSTAT_INFO_AUTOMOUNT;
+	if (IS_POSIXACL(inode))
+		stat->information |= XSTAT_INFO_HAS_ACL;
+
+	/* if unset, assume 1s granularity */
+	stat->tv_granularity = sb->s_time_gran ?: 1000000000U;
+
+	if (unlikely(S_ISBLK(stat->mode) || S_ISCHR(stat->mode)))
+		stat->result_mask |= XSTAT_RDEV;
+
+	x  = ((u32*)&stat->volume_id)[0] = ((u32*)&sb->s_volume_id)[0];
+	x |= ((u32*)&stat->volume_id)[1] = ((u32*)&sb->s_volume_id)[1];
+	x |= ((u32*)&stat->volume_id)[2] = ((u32*)&sb->s_volume_id)[2];
+	x |= ((u32*)&stat->volume_id)[3] = ((u32*)&sb->s_volume_id)[3];
+	if (x)
+		stat->result_mask |= XSTAT_VOLUME_ID;
+}
 EXPORT_SYMBOL(generic_fillattr);
 
-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+/**
+ * vfs_xgetattr - Get the basic and extra attributes of a file
+ * @mnt: The mountpoint to which the dentry belongs
+ * @dentry: The file of interest
+ * @stat: Where to return the statistics
+ *
+ * Ask the filesystem for a file's attributes.  The caller must have preset
+ * stat->request_mask and stat->query_flags to indicate what they want.
+ *
+ * If the file is remote, the filesystem can be forced to update the attributes
+ * from the backing store by passing AT_FORCE_ATTR_SYNC in query_flags.
+ *
+ * Bits must have been set in stat->request_mask to indicate which attributes
+ * the caller wants retrieving.  Any such attribute not requested may be
+ * returned anyway, but the value may be approximate, and, if remote, may not
+ * have been synchronised with the server.
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_xgetattr(struct vfsmount *mnt, struct dentry *dentry,
+		 struct kstat *stat)
 {
 	struct inode *inode = dentry->d_inode;
 	int retval;
@@ -46,65 +102,186 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 	if (retval)
 		return retval;
 
+	stat->result_mask = 0;
+	stat->information = 0;
+	stat->ioc_flags = 0;
 	if (inode->i_op->getattr)
 		return inode->i_op->getattr(mnt, dentry, stat);
 
 	generic_fillattr(inode, stat);
 	return 0;
 }
+EXPORT_SYMBOL(vfs_xgetattr);
 
+/**
+ * vfs_getattr - Get the basic attributes of a file
+ * @mnt: The mountpoint to which the dentry belongs
+ * @dentry: The file of interest
+ * @stat: Where to return the statistics
+ *
+ * Ask the filesystem for a file's attributes.  If remote, the filesystem isn't
+ * forced to update its files from the backing store. Only the basic set of
+ * attributes will be retrieved; anyone wanting more must use vfs_getxattr(),
+ * as must anyone who wants to force attributes to be sync'd with the server.
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+	stat->query_flags = 0;
+	stat->request_mask = XSTAT_BASIC_STATS;
+	return vfs_xgetattr(mnt, dentry, stat);
+}
 EXPORT_SYMBOL(vfs_getattr);
 
-int vfs_fstat(unsigned int fd, struct kstat *stat)
+/**
+ * vfs_fxstat - Get basic and extra attributes by file descriptor
+ * @fd: The file descriptor refering to the file of interest
+ * @stat: The result structure to fill in.
+ *
+ * This function is a wrapper around vfs_xgetattr(). The main difference is
+ * that is uses a file descriptor to determine the file location.
+ *
+ * The caller must have preset stat->query_flags and stat->request_mask as for
+ * vfs_xgetattr().
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_fxstat(unsigned int fd, struct kstat *stat)
 {
 	int fput_needed;
 	struct file *f = fget_light(fd, &fput_needed);
 	int error = -EBADF;
 
+	if (stat->query_flags & ~KSTAT_QUERY_FLAGS)
+		return -EINVAL;
 	if (f) {
-		error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
+		error = vfs_xgetattr(f->f_path.mnt, f->f_path.dentry, stat);
 		fput_light(f, fput_needed);
 	}
 	return error;
 }
+EXPORT_SYMBOL(vfs_fxstat);
+
+/**
+ * vfs_fstat - Get basic attributes by file descriptor
+ * @fd: The file descriptor refering to the file of interest
+ * @stat: The result structure to fill in.
+ *
+ * This function is a wrapper around vfs_getattr(). The main difference is
+ * that it uses a file descriptor to determine the file location.
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_fstat(unsigned int fd, struct kstat *stat)
+{
+	stat->query_flags = 0;
+	stat->request_mask = XSTAT_BASIC_STATS;
+	return vfs_fxstat(fd, stat);
+}
 EXPORT_SYMBOL(vfs_fstat);
 
-int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
-		int flag)
+/**
+ * vfs_xstat - Get basic and extra attributes by filename
+ * @dfd: A file descriptor respresenting the base dir for a relative filename
+ * @filename: The name of the file of interest
+ * @flags: Flags to control the query
+ * @stat: The result structure to fill in.
+ *
+ * This function is a wrapper around vfs_xgetattr(). The main difference is
+ * that it uses a filename and base directory to determine the file location.
+ * Additionally, the addition of AT_SYMLINK_NOFOLLOW to flags will prevent a
+ * symlink at the given name from being referenced.
+ *
+ * The caller must have preset stat->request_mask as for vfs_xgetattr(). The
+ * flags are also used to load up stat->query_flags.
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_xstat(int dfd, const char __user *filename, int flags,
+	      struct kstat *stat)
 {
 	struct path path;
-	int error = -EINVAL;
-	int lookup_flags = 0;
+	int error, lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
 
-	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
-		      AT_EMPTY_PATH)) != 0)
-		goto out;
+	if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
+		       AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
+		return -EINVAL;
 
-	if (!(flag & AT_SYMLINK_NOFOLLOW))
-		lookup_flags |= LOOKUP_FOLLOW;
-	if (flag & AT_EMPTY_PATH)
+	if (flags & AT_SYMLINK_NOFOLLOW)
+		lookup_flags &= ~LOOKUP_FOLLOW;
+	if (flags & AT_NO_AUTOMOUNT)
+		lookup_flags &= ~LOOKUP_AUTOMOUNT;
+	if (flags & AT_EMPTY_PATH)
 		lookup_flags |= LOOKUP_EMPTY;
 
+	stat->query_flags = flags & KSTAT_QUERY_FLAGS;
 	error = user_path_at(dfd, filename, lookup_flags, &path);
-	if (error)
-		goto out;
-
-	error = vfs_getattr(path.mnt, path.dentry, stat);
-	path_put(&path);
-out:
+	if (!error) {
+		error = vfs_xgetattr(path.mnt, path.dentry, stat);
+		path_put(&path);
+	}
 	return error;
 }
+EXPORT_SYMBOL(vfs_xstat);
+
+/**
+ * vfs_fstatat - Get basic attributes by filename
+ * @dfd: A file descriptor representing the base dir for a relative filename
+ * @filename: The name of the file of interest
+ * @flags: Flags to control the query
+ * @stat: The result structure to fill in.
+ *
+ * This function is a wrapper around vfs_xstat().  The difference is that it
+ * preselects basic stats only.  The flags are used to load up
+ * stat->query_flags in addition to indicating symlink handling during path
+ * resolution.
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
+		int flags)
+{
+	stat->request_mask = XSTAT_BASIC_STATS;
+	return vfs_xstat(dfd, filename, flags, stat);
+}
 EXPORT_SYMBOL(vfs_fstatat);
 
-int vfs_stat(const char __user *name, struct kstat *stat)
+/**
+ * vfs_stat - Get basic attributes by filename
+ * @filename: The name of the file of interest
+ * @stat: The result structure to fill in.
+ *
+ * This function is a wrapper around vfs_xstat().  The difference is that it
+ * preselects basic stats only, terminal symlinks are followed regardless and a
+ * remote filesystem can't be forced to query the server.  If such is desired,
+ * vfs_xstat() should be used instead.
+ *
+ * 0 will be returned on success, and a -ve error code if unsuccessful.
+ */
+int vfs_stat(const char __user *filename, struct kstat *stat)
 {
-	return vfs_fstatat(AT_FDCWD, name, stat, 0);
+	stat->request_mask = XSTAT_BASIC_STATS;
+	return vfs_xstat(AT_FDCWD, filename, 0, stat);
 }
 EXPORT_SYMBOL(vfs_stat);
 
+/**
+ * vfs_lstat - Get basic attributes by filename, without following terminal symlink
+ * @filename: The name of the file of interest
+ * @stat: The result structure to fill in.
+ *
+ * This function is a wrapper around vfs_xstat(). The difference is that it
+ * preselects basic stats only, terminal symlinks are not followed regardless
+ * and a remote filesystem can't be forced to query the server. If such is
+ * desired, vfs_xstat() should be used instead.
+ *
+ * 0 is returned on success, and a -ve error code if unsuccessful.
+ */
 int vfs_lstat(const char __user *name, struct kstat *stat)
 {
-	return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW);
+	stat->request_mask = XSTAT_BASIC_STATS;
+	return vfs_xstat(AT_FDCWD, name, AT_SYMLINK_NOFOLLOW, stat);
 }
 EXPORT_SYMBOL(vfs_lstat);
 
@@ -119,7 +296,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
 {
 	static int warncount = 5;
 	struct __old_kernel_stat tmp;
-	
+
 	if (warncount > 0) {
 		warncount--;
 		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
@@ -144,7 +321,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
 #if BITS_PER_LONG == 32
 	if (stat->size > MAX_NON_LFS)
 		return -EOVERFLOW;
-#endif	
+#endif
 	tmp.st_size = stat->size;
 	tmp.st_atime = stat->atime.tv_sec;
 	tmp.st_mtime = stat->mtime.tv_sec;
@@ -417,6 +594,143 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
 }
 #endif /* __ARCH_WANT_STAT64 */
 
+static inline void xstat_get_params_i(unsigned int mask, struct kstat *stat)
+{
+	memset(stat, 0xde, sizeof(*stat)); // DEBUGGING
+
+	stat->request_mask = mask & XSTAT_ALL_STATS;
+	stat->result_mask = 0;
+}
+/*
+ * Get the xstat parameters if supplied
+ */
+static int xstat_get_params(unsigned int mask, struct xstat __user *buffer,
+			    struct kstat *stat)
+{
+	if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer)))
+		return -EFAULT;
+
+	xstat_get_params_i(mask, stat);
+	return 0;
+}
+
+/*
+ * Get the xstat parameters with a xdirent
+ */
+int xdirent_get_params(unsigned int mask, struct kstat *stat)
+{
+	xstat_get_params_i(mask, stat);
+	return 0;
+}
+EXPORT_SYMBOL(xdirent_get_params);
+
+/*
+ * Set the xstat results
+ *
+ * If the buffer size was 0, we just return the size of the buffer needed to
+ * return the full result.
+ *
+ * If bufsize indicates a buffer of insufficient size to hold the full result,
+ * we return -E2BIG.
+ *
+ * Otherwise we copy the extended stats to userspace and return the amount of
+ * data written into the buffer (or -EFAULT).
+ */
+long xstat_set_result(struct kstat *stat, struct xstat __user *buffer)
+{
+	u32 mask = stat->result_mask, gran = stat->tv_granularity;
+
+#define __put_timestamp(kts, uts) (                                        \
+		__put_user(kts.tv_sec,  uts.tv_sec                   ) ||  \
+		__put_user(kts.tv_nsec, uts.tv_nsec                  ) ||  \
+		__put_user(gran,        uts.tv_granularity           ))
+
+	/* clear out anything we're not returning */
+	if (!(mask & XSTAT_IOC_FLAGS))
+		stat->ioc_flags = 0;
+	if (!(mask & XSTAT_BTIME))
+		memset(&stat->btime, 0, sizeof(stat->btime));
+	if (!(mask & XSTAT_GEN))
+		stat->gen = 0;
+	if (!(mask & XSTAT_VERSION))
+		stat->version = 0;
+	if (!(mask & XSTAT_VOLUME_ID))
+		memset(&stat->volume_id, 0, sizeof(stat->volume_id));
+
+	/* transfer the results */
+	if (__put_user(mask,                     &buffer->st_mask          ) ||
+	    __put_user(stat->mode,               &buffer->st_mode          ) ||
+	    __put_user(stat->nlink,              &buffer->st_nlink         ) ||
+	    __put_user(stat->uid,                &buffer->st_uid           ) ||
+	    __put_user(stat->gid,                &buffer->st_gid           ) ||
+	    __put_user(stat->information,        &buffer->st_information   ) ||
+	    __put_user(stat->ioc_flags,          &buffer->st_ioc_flags     ) ||
+	    __put_user(stat->blksize,            &buffer->st_blksize       ) ||
+	    __put_user(MAJOR(stat->rdev),        &buffer->st_rdev.major    ) ||
+	    __put_user(MINOR(stat->rdev),        &buffer->st_rdev.minor    ) ||
+	    __put_user(MAJOR(stat->dev),         &buffer->st_dev.major     ) ||
+	    __put_user(MINOR(stat->dev),         &buffer->st_dev.minor     ) ||
+	    __put_timestamp(stat->atime,         &buffer->st_atime         ) ||
+	    __put_timestamp(stat->btime,         &buffer->st_btime         ) ||
+	    __put_timestamp(stat->ctime,         &buffer->st_ctime         ) ||
+	    __put_timestamp(stat->mtime,         &buffer->st_mtime         ) ||
+	    __put_user(stat->ino,                &buffer->st_ino           ) ||
+	    __put_user(stat->size,               &buffer->st_size          ) ||
+	    __put_user(stat->blocks,             &buffer->st_blocks        ) ||
+	    __put_user(stat->gen,                &buffer->st_gen           ) ||
+	    __put_user(stat->version,            &buffer->st_version       ) ||
+	    __copy_to_user(&buffer->st_volume_id, &stat->volume_id,
+			   sizeof(buffer->st_volume_id)                    ) ||
+	    __clear_user(&buffer->__spares, sizeof(buffer->__spares)))
+		return -EFAULT;
+	return 0;
+}
+
+long xdirent_set_result(struct kstat *stat, void __user *buffer)
+{
+	struct linux_xdirent __user *xdirent = (struct linux_xdirent *) buffer;
+	return xstat_set_result(stat, &xdirent->x_st);
+}
+
+/*
+ * System call to get extended stats by path
+ */
+SYSCALL_DEFINE5(xstat,
+		int, dfd, const char __user *, filename, unsigned, flags,
+		unsigned int, mask, struct xstat __user *, buffer)
+{
+	struct kstat stat;
+	int error;
+
+	error = xstat_get_params(mask, buffer, &stat);
+	if (error != 0)
+		return error;
+	error = vfs_xstat(dfd, filename, flags, &stat);
+	if (error)
+		return error;
+	return xstat_set_result(&stat, buffer);
+}
+
+/*
+ * System call to get extended stats by file descriptor
+ */
+SYSCALL_DEFINE4(fxstat,
+		unsigned int, fd, unsigned int, flags,
+		unsigned int, mask, struct xstat __user *, buffer)
+{
+	struct kstat stat;
+	int error;
+
+	error = xstat_get_params(mask, buffer, &stat);
+	if (error < 0)
+		return error;
+	stat.query_flags = flags;
+	error = vfs_fxstat(fd, &stat);
+	if (error)
+		return error;
+	return xstat_set_result(&stat, buffer);
+}
+
 /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
 void __inode_add_bytes(struct inode *inode, loff_t bytes)
 {
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index f550f89..9c84e23 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -47,6 +47,7 @@
 #define AT_SYMLINK_FOLLOW	0x400   /* Follow symbolic links.  */
 #define AT_NO_AUTOMOUNT		0x800	/* Suppress terminal automount traversal */
 #define AT_EMPTY_PATH		0x1000	/* Allow empty relative pathname */
+#define AT_FORCE_ATTR_SYNC      0x2000  /* Force the attributes to be sync'd with the server */
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 38dba16..b3974df 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1539,6 +1539,7 @@ struct super_block {
 
 	char s_id[32];				/* Informational name */
 	u8 s_uuid[16];				/* UUID */
+	unsigned char           s_volume_id[16]; /* Volume identifier */
 
 	void 			*s_fs_info;	/* Filesystem private info */
 	unsigned int		s_max_links;
@@ -1767,6 +1768,10 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
  * to have different dirent layouts depending on the binary type.
  */
 typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
+/*
+ * Extended filldir function to return kstat as well
+ */
+typedef int (*xfilldir_t)(void *, const char *, int, loff_t, u64, unsigned, struct kstat *);
 struct block_device_operations;
 
 /* These macros are for out of kernel modules to test that
@@ -1783,6 +1788,7 @@ struct file_operations {
 	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
 	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
 	int (*readdir) (struct file *, void *, filldir_t);
+	int (*xreaddir) (struct file *, void *, xfilldir_t, unsigned flags, unsigned int mask);
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
 	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
@@ -2657,6 +2663,7 @@ extern const struct inode_operations page_symlink_inode_operations;
 extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int vfs_xgetattr(struct vfsmount *, struct dentry *, struct kstat *);
 void __inode_add_bytes(struct inode *inode, loff_t bytes);
 void inode_add_bytes(struct inode *inode, loff_t bytes);
 void inode_sub_bytes(struct inode *inode, loff_t bytes);
@@ -2669,6 +2676,8 @@ extern int vfs_stat(const char __user *, struct kstat *);
 extern int vfs_lstat(const char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
+extern int vfs_xstat(int, const char __user *, int, struct kstat *);
+extern int vfs_fxstat(unsigned int, struct kstat *);
 
 extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 		    unsigned long arg);
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 4613240..cc9535a 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -3,6 +3,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
 #include <asm/stat.h>
 
 #endif
@@ -46,6 +47,117 @@
 
 #endif
 
+/*
+ * Query request/result mask
+ *
+ * Bits should be set in request_mask to request particular items when calling
+ * xstat() or fxstat().
+ *
+ * The bits in st_mask may or may not be set upon return, in part depending on
+ * what was set in the mask argument:
+ *
+ * - if not available at all, the bit will be cleared before returning and the
+ *   field will be cleared; otherise,
+ *
+ * - if AT_FORCE_ATTR_SYNC is set, then the datum will be synchronised to the
+ *   server and the field and bit will be set on return; otherwise,
+ *
+ * - if explicitly requested, the datum will be synchronised to a serer or
+ *   other medium if out of date before being returned, and the bit will be set
+ *   on return; otherwise,
+ *
+ * - if not requested, but available in approximate form without any effort, it
+ *   will be filled in anyway, and the bit will be set upon return  (it might
+ *   not be up to date, however, and no attempt will be made to synchronise the
+ *   internal state first); otherwise,
+ *
+ * - the field and the bit will be cleared before returning.
+ *
+ * Items in XSTAT_BASIC_STATS may be marked unavailable on return, but they
+ * will have a value installed for compatibility purposes so that stat() and
+ * co. can be emulated in userspace.
+ */
+#define XSTAT_MODE             0x00000001U     /* want/got st_mode */
+#define XSTAT_NLINK            0x00000002U     /* want/got st_nlink */
+#define XSTAT_UID              0x00000004U     /* want/got st_uid */
+#define XSTAT_GID              0x00000008U     /* want/got st_gid */
+#define XSTAT_RDEV             0x00000010U     /* want/got st_rdev */
+#define XSTAT_ATIME            0x00000020U     /* want/got st_atime */
+#define XSTAT_MTIME            0x00000040U     /* want/got st_mtime */
+#define XSTAT_CTIME            0x00000080U     /* want/got st_ctime */
+#define XSTAT_INO              0x00000100U     /* want/got st_ino */
+#define XSTAT_SIZE             0x00000200U     /* want/got st_size */
+#define XSTAT_BLOCKS           0x00000400U     /* want/got st_blocks */
+#define XSTAT_BASIC_STATS      0x000007ffU     /* the stuff in the normal stat struct */
+#define XSTAT_IOC_FLAGS        0x00000800U     /* want/got FS_IOC_GETFLAGS */
+#define XSTAT_BTIME            0x00001000U     /* want/got st_btime */
+#define XSTAT_GEN              0x00002000U     /* want/got st_gen */
+#define XSTAT_VERSION          0x00004000U     /* want/got st_version */
+#define XSTAT_VOLUME_ID        0x00008000U     /* want/got st_volume_id */
+#define XSTAT_ALL_STATS        0x0000ffffU     /* all supported stats */
+
+/*
+ * Extended stat structures
+ */
+struct xstat_dev {
+	uint32_t                major, minor;
+};
+
+struct xstat_time {
+	int64_t                 tv_sec;
+	uint32_t                tv_nsec;
+	uint32_t                tv_granularity; /* time granularity (in nS) */
+};
+
+struct xstat {
+	uint32_t                st_mask;        /* what results were written */
+	uint32_t                st_mode;        /* file mode */
+	uint32_t                st_nlink;       /* number of hard links */
+	uint32_t                st_uid;         /* user ID of owner */
+	uint32_t                st_gid;         /* group ID of owner */
+	uint32_t                st_information; /* information about the file */
+	uint32_t                st_ioc_flags;   /* as FS_IOC_GETFLAGS */
+	uint32_t                st_blksize;     /* optimal size for filesystem I/O */
+	struct xstat_dev        st_rdev;        /* device ID of special file */
+	struct xstat_dev        st_dev;         /* ID of device containing file */
+	struct xstat_time       st_atime;       /* last access time */
+	struct xstat_time       st_btime;       /* file creation time */
+	struct xstat_time       st_ctime;       /* last attribute change time */
+	struct xstat_time       st_mtime;       /* last data modification time */
+	uint64_t                st_ino;         /* inode number */
+	uint64_t                st_size;        /* file size */
+	uint64_t                st_blocks;      /* number of 512-byte blocks allocated */
+	uint64_t                st_gen;         /* inode generation number */
+	uint64_t                st_version;     /* data version number */
+	uint8_t                 st_volume_id[16]; /* volume identifier */
+	uint64_t                __spares[11];   /* spare space for future expansion */
+};
+
+/*
+ * Flags to be found in st_information
+ *
+ * These give information about the features or the state of a file that might
+ * be of use to ordinary userspace programs such as GUIs or ls rather than
+ * specialised tools.
+ *
+ * Additional information may be found in st_ioc_flags and we try not to
+ * overlap with it.
+ */
+#define XSTAT_INFO_ENCRYPTED           0x00000001U /* File is encrypted */
+#define XSTAT_INFO_TEMPORARY           0x00000002U /* File is temporary (NTFS/CIFS) */
+#define XSTAT_INFO_FABRICATED          0x00000004U /* File was made up by filesystem */
+#define XSTAT_INFO_KERNEL_API          0x00000008U /* File is kernel API (eg: procfs/sysfs) */
+#define XSTAT_INFO_REMOTE              0x00000010U /* File is remote */
+#define XSTAT_INFO_OFFLINE             0x00000020U /* File is offline (CIFS) */
+#define XSTAT_INFO_AUTOMOUNT           0x00000040U /* Dir is automount trigger */
+#define XSTAT_INFO_AUTODIR             0x00000080U /* Dir provides unlisted automounts */
+#define XSTAT_INFO_NONSYSTEM_OWNERSHIP 0x00000100U /* File has non-system ownership details */
+#define XSTAT_INFO_HAS_ACL             0x00000200U /* File has an ACL of some sort */
+#define XSTAT_INFO_REPARSE_POINT       0x00000400U /* File is reparse point (NTFS/CIFS) */
+#define XSTAT_INFO_HIDDEN              0x00000800U /* File is marked hidden (DOS+) */
+#define XSTAT_INFO_SYSTEM              0x00001000U /* File is marked system (DOS+) */
+#define XSTAT_INFO_ARCHIVE             0x00002000U /* File is marked archive (DOS+) */
+
 #ifdef __KERNEL__
 #define S_IRWXUGO	(S_IRWXU|S_IRWXG|S_IRWXO)
 #define S_IALLUGO	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
@@ -61,6 +173,12 @@
 #include <linux/uidgid.h>
 
 struct kstat {
+	u32             query_flags;                /* operational flags */
+#define KSTAT_QUERY_FLAGS (AT_FORCE_ATTR_SYNC)
+	u32             request_mask;               /* what fields the user asked for */
+	u32             result_mask;                /* what fields the user got */
+	u32             information;
+	u32             ioc_flags;                  /* inode flags (FS_IOC_GETFLAGS) */
 	u64		ino;
 	dev_t		dev;
 	umode_t		mode;
@@ -68,14 +186,40 @@ struct kstat {
 	kuid_t		uid;
 	kgid_t		gid;
 	dev_t		rdev;
+	unsigned int    tv_granularity;             /* granularity of times (in nS) */
 	loff_t		size;
-	struct timespec  atime;
+	struct timespec atime;
 	struct timespec	mtime;
 	struct timespec	ctime;
+	struct timespec btime;                      /* file creation time */
 	unsigned long	blksize;
 	unsigned long long	blocks;
+	u64             gen;                        /* inode generation */
+	u64             version;                    /* data version */
+	unsigned char   volume_id[16];              /* volume identifier */
 };
 
-#endif
+/*
+ * New, all-improved, singing, dancing, iBCS2-compliant getdents()
+ * interface. 
+ */
+struct linux_dirent {
+	unsigned long	d_ino;
+	unsigned long	d_off;
+	unsigned short	d_reclen;
+	char		d_name[1];
+};
 
+/*
+ * Extended dirent. x_dent.d_reclen contains the combined length of x_dent and x_st
+ */
+struct linux_xdirent {
+	struct xstat        x_st;
+	struct linux_dirent x_dent;
+};
+
+long xstat_set_result(struct kstat *stat, struct xstat __user *buffer);
+long xdirent_set_result(struct kstat *stat, void __user *buffer);
+int xdirent_get_params(unsigned int mask, struct kstat *stat);
+#endif
 #endif
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 19439c7..36ce855 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -860,4 +860,9 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
 
 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
 			 unsigned long idx1, unsigned long idx2);
+
+asmlinkage long sys_xstat(int dfd, const char __user *path, unsigned flags,
+			  unsigned mask, struct xstat __user *buffer);
+asmlinkage long sys_fxstat(unsigned fd, unsigned flags,
+			   unsigned mask, struct xstat __user *buffer);
 #endif
