* [patch] add flags to stat()
@ 2006-08-06 15:58 Ameer Armaly
2006-08-07 7:11 ` Josef Sipek
2006-08-07 14:23 ` Matthew Wilcox
0 siblings, 2 replies; 6+ messages in thread
From: Ameer Armaly @ 2006-08-06 15:58 UTC (permalink / raw)
To: linux-fsdevel
Hi all.
This is my first serious attempt at kernel hacking, so here goes. I was
reading in LWN concerning the idea of adding flags to the stat system call, so
that applications could request specific items they wanted as opposed to
having to deal with the whole stat struct. Here is a patch that does just
that. It ads a new parameter to the stat family including stat, stat64,
and stat (and all their variants) to contain flags, and defines a flag for
each entry in the stat structure. These flags are passed down the chain
through the various vfs functions, and finally to the individual
filesystem. This is where it hits a snag: each filesystem has to
implement the actual processing of the flags on its own. However, it
still seems to run fine even with these changes, so backwards
compatibility doesn't appear to be a problem. If anyone knows some
sources to read of a more efficient way to implement something like this,
please let me know. All the kernel interfaces I have seen that use stat
have been modified to pass 0 (give me everything) for now; we can optimize
them later. Thoughts?
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 7b3b94d..73c60cf 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1008,7 +1008,7 @@ loop_get_status(struct loop_device *lo,
if (lo->lo_state != Lo_bound)
return -ENXIO;
- error = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
+ error = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat, 0);
if (error)
return error;
memset(info, 0, sizeof(*info));
diff --git a/fs/stat.c b/fs/stat.c
index 3a44dcf..a2cdba8 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -37,7 +37,7 @@ void generic_fillattr(struct inode *inod
EXPORT_SYMBOL(generic_fillattr);
-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat, unsigned int flags)
{
struct inode *inode = dentry->d_inode;
int retval;
@@ -47,10 +47,10 @@ int vfs_getattr(struct vfsmount *mnt, st
return retval;
if (inode->i_op->getattr)
- return inode->i_op->getattr(mnt, dentry, stat);
+ return inode->i_op->getattr(mnt, dentry, stat, flags);
generic_fillattr(inode, stat);
- if (!stat->blksize) {
+ if (!stat->blksize && flags & S_GETBLKSIZE) {
struct super_block *s = inode->i_sb;
unsigned blocks;
blocks = (stat->size+s->s_blocksize-1) >> s->s_blocksize_bits;
@@ -62,53 +62,53 @@ int vfs_getattr(struct vfsmount *mnt, st
EXPORT_SYMBOL(vfs_getattr);
-int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
+int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat, unsigned int flags)
{
struct nameidata nd;
int error;
error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
if (!error) {
- error = vfs_getattr(nd.mnt, nd.dentry, stat);
+ error = vfs_getattr(nd.mnt, nd.dentry, stat, flags);
path_release(&nd);
}
return error;
}
-int vfs_stat(char __user *name, struct kstat *stat)
+int vfs_stat(char __user *name, struct kstat *stat, unsigned int flags)
{
- return vfs_stat_fd(AT_FDCWD, name, stat);
+ return vfs_stat_fd(AT_FDCWD, name, stat, flags);
}
EXPORT_SYMBOL(vfs_stat);
-int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
+int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat, unsigned int flags)
{
struct nameidata nd;
int error;
error = __user_walk_fd(dfd, name, 0, &nd);
if (!error) {
- error = vfs_getattr(nd.mnt, nd.dentry, stat);
+ error = vfs_getattr(nd.mnt, nd.dentry, stat, flags);
path_release(&nd);
}
return error;
}
-int vfs_lstat(char __user *name, struct kstat *stat)
+int vfs_lstat(char __user *name, struct kstat *stat, unsigned int flags)
{
- return vfs_lstat_fd(AT_FDCWD, name, stat);
+ return vfs_lstat_fd(AT_FDCWD, name, stat, flags);
}
EXPORT_SYMBOL(vfs_lstat);
-int vfs_fstat(unsigned int fd, struct kstat *stat)
+int vfs_fstat(unsigned int fd, struct kstat *stat, unsigned int flags)
{
struct file *f = fget(fd);
int error = -EBADF;
if (f) {
- error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat);
+ error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat, flags);
fput(f);
}
return error;
@@ -160,7 +160,7 @@ #endif
asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf)
{
struct kstat stat;
- int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
+ int error = vfs_stat_fd(AT_FDCWD, filename, &stat, 0);
if (!error)
error = cp_old_stat(&stat, statbuf);
@@ -170,7 +170,7 @@ asmlinkage long sys_stat(char __user * f
asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf)
{
struct kstat stat;
- int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
+ int error = vfs_lstat_fd(AT_FDCWD, filename, &stat, 0);
if (!error)
error = cp_old_stat(&stat, statbuf);
@@ -180,7 +180,7 @@ asmlinkage long sys_lstat(char __user *
asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat __user * statbuf)
{
struct kstat stat;
- int error = vfs_fstat(fd, &stat);
+ int error = vfs_fstat(fd, &stat, 0);
if (!error)
error = cp_old_stat(&stat, statbuf);
@@ -238,10 +238,13 @@ #endif
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
-asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf)
+asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf, unsigned int flags)
{
struct kstat stat;
- int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
+ int error;
+ if(!flags) /*The want everything, so let's flip on all the flags.*/
+ --flags;
+ error = vfs_stat_fd(AT_FDCWD, filename, &stat, flags);
if (!error)
error = cp_new_stat(&stat, statbuf);
@@ -249,10 +252,13 @@ asmlinkage long sys_newstat(char __user
return error;
}
-asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf)
+asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf, unsigned int flags)
{
struct kstat stat;
- int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
+ int error;
+ if(!flags) /*The want everything, so let's flip on all the flags.*/
+ --flags;
+ error = vfs_lstat_fd(AT_FDCWD, filename, &stat, flags);
if (!error)
error = cp_new_stat(&stat, statbuf);
@@ -262,16 +268,17 @@ asmlinkage long sys_newlstat(char __user
#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT)
asmlinkage long sys_newfstatat(int dfd, char __user *filename,
- struct stat __user *statbuf, int flag)
+ struct stat __user *statbuf, int flag, unsigned int statflags)
{
- struct kstat stat;
int error = -EINVAL;
-
+ struct kstat stat;
+ if(!statflags) /*The want everything, so let's flip on all the flags.*/
+ --statflags;
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
goto out;
if (flag & AT_SYMLINK_NOFOLLOW)
- error = vfs_lstat_fd(dfd, filename, &stat);
+ error = vfs_lstat_fd(dfd, filename, &stat, statflags);
else
error = vfs_stat_fd(dfd, filename, &stat);
@@ -283,10 +290,13 @@ out:
}
#endif
-asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf)
+asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf, unsigned int statflags)
{
struct kstat stat;
- int error = vfs_fstat(fd, &stat);
+ int error;
+ if(!statflags) /*The want everything, so let's flip on all the flags.*/
+ --statflags;
+ error = vfs_fstat(fd, &stat, statflags);
if (!error)
error = cp_new_stat(&stat, statbuf);
@@ -365,30 +375,38 @@ #endif
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
-asmlinkage long sys_stat64(char __user * filename, struct stat64 __user * statbuf)
+asmlinkage long sys_stat64(char __user * filename, struct stat64 __user * statbuf, unsigned int flags)
{
struct kstat stat;
- int error = vfs_stat(filename, &stat);
+ int error;
+ if(!flags) /*The want everything, so let's flip on all the flags.*/
+ --flags;
+ error = vfs_stat(filename, &stat, flags);
if (!error)
error = cp_new_stat64(&stat, statbuf);
return error;
}
-asmlinkage long sys_lstat64(char __user * filename, struct stat64 __user * statbuf)
+asmlinkage long sys_lstat64(char __user * filename, struct stat64 __user * statbuf, unsigned int flags)
{
- struct kstat stat;
- int error = vfs_lstat(filename, &stat);
-
+ struct kstat stat;
+ int error;
+ if(!flags) /*The want everything, so let's flip on all the flags.*/
+ --flags;
+ error = vfs_lstat(filename, &stat, flags);
if (!error)
error = cp_new_stat64(&stat, statbuf);
return error;
}
-asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf)
+asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf, unsigned int flags)
{
struct kstat stat;
- int error = vfs_fstat(fd, &stat);
+ int error;
+ if(!flags) /*The want everything, so let's flip on all the flags.*/
+ --flags;
+ error = vfs_fstat(fd, &stat, flags);
if (!error)
error = cp_new_stat64(&stat, statbuf);
@@ -397,18 +415,20 @@ asmlinkage long sys_fstat64(unsigned lon
}
asmlinkage long sys_fstatat64(int dfd, char __user *filename,
- struct stat64 __user *statbuf, int flag)
+ struct stat64 __user *statbuf, int flag, unsigned int statflags)
{
struct kstat stat;
+ if(!statflags) /*The want everything, so let's flip on all the flags.*/
+ --statflags;
int error = -EINVAL;
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
goto out;
if (flag & AT_SYMLINK_NOFOLLOW)
- error = vfs_lstat_fd(dfd, filename, &stat);
+ error = vfs_lstat_fd(dfd, filename, &stat, statflags);
else
- error = vfs_stat_fd(dfd, filename, &stat);
+ error = vfs_stat_fd(dfd, filename, &stat, statflags);
if (!error)
error = cp_new_stat64(&stat, statbuf);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2561020..252dc1a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -40,6 +40,7 @@ struct files_stat_struct {
extern struct files_stat_struct files_stat;
extern int get_max_files(void);
+
struct inodes_stat_t {
int nr_inodes;
int nr_unused;
@@ -1099,7 +1100,7 @@ struct inode_operations {
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, struct nameidata *);
int (*setattr) (struct dentry *, struct iattr *);
- int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
+ int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *, unsigned int flags);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
@@ -1764,7 +1765,7 @@ extern int page_symlink(struct inode *in
extern 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_getattr(struct vfsmount *, struct dentry *, struct kstat *, unsigned int);
void inode_add_bytes(struct inode *inode, loff_t bytes);
void inode_sub_bytes(struct inode *inode, loff_t bytes);
loff_t inode_get_bytes(struct inode *inode);
@@ -1772,11 +1773,11 @@ void inode_set_bytes(struct inode *inode
extern int vfs_readdir(struct file *, filldir_t, void *);
-extern int vfs_stat(char __user *, struct kstat *);
-extern int vfs_lstat(char __user *, struct kstat *);
-extern int vfs_stat_fd(int dfd, char __user *, struct kstat *);
-extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *);
-extern int vfs_fstat(unsigned int, struct kstat *);
+extern int vfs_stat(char __user *, struct kstat *, unsigned int);
+extern int vfs_lstat(char __user *, struct kstat *, unsigned int);
+extern int vfs_stat_fd(int dfd, char __user *, struct kstat *, unsigned int);
+extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *, unsigned int);
+extern int vfs_fstat(unsigned int, struct kstat *, unsigned int);
extern int vfs_ioctl(struct file *, unsigned int, unsigned int, unsigned long);
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 8669291..7f607e2 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -72,6 +72,21 @@ struct kstat {
unsigned long long blocks;
};
+/* Flags for the construction of a stat structure as opposed to getting the whole thing. */
+#define S_GETDEV 0x001
+#define S_GETINODE 0x002
+#define S_GETMODE 0x004
+#define S_GETNLINK 0x008
+#define S_GETUID 0x010
+#define S_GETGID 0x020
+#define S_GETRDEV 0x040
+#define S_GETSIZE 0x080
+#define S_GETBLKSIZE 0x100
+#define S_GETBLOCKS 0x100
+#define S_GETATIME 0x200
+#define S_GETMTIME 0x400
+#define S_GETCTIME 0x800
+
#endif
#endif
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 008f04c..f3a993c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -225,17 +225,17 @@ asmlinkage long sys_lstat(char __user *f
asmlinkage long sys_fstat(unsigned int fd,
struct __old_kernel_stat __user *statbuf);
asmlinkage long sys_newstat(char __user *filename,
- struct stat __user *statbuf);
+ struct stat __user *statbuf, unsigned int flags);
asmlinkage long sys_newlstat(char __user *filename,
- struct stat __user *statbuf);
-asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf);
+ struct stat __user *statbuf, unsigned int flags);
+asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf, unsigned int flags);
asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf);
#if BITS_PER_LONG == 32
asmlinkage long sys_stat64(char __user *filename,
- struct stat64 __user *statbuf);
-asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
+ struct stat64 __user *statbuf, unsigned int flags);
+asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf, unsigned int flags);
asmlinkage long sys_lstat64(char __user *filename,
- struct stat64 __user *statbuf);
+ struct stat64 __user *statbuf, unsigned int flags);
asmlinkage long sys_truncate64(const char __user *path, loff_t length);
asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
#endif
@@ -568,7 +568,7 @@ asmlinkage long sys_openat(int dfd, cons
asmlinkage long sys_newfstatat(int dfd, char __user *filename,
struct stat __user *statbuf, int flag);
asmlinkage long sys_fstatat64(int dfd, char __user *filename,
- struct stat64 __user *statbuf, int flag);
+ struct stat64 __user *statbuf, int flag, unsigned int statflags);
asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf,
int bufsiz);
asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename,
diff --git a/init/do_mounts.h b/init/do_mounts.h
index e7f2e7f..e65b6fa 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -24,7 +24,7 @@ #if BITS_PER_LONG == 32
static inline u32 bstat(char *name)
{
struct stat64 stat;
- if (sys_stat64(name, &stat) != 0)
+ if (sys_stat64(name, &stat, 0) != 0)
return 0;
if (!S_ISBLK(stat.st_mode))
return 0;
@@ -36,7 +36,7 @@ #else
static inline u32 bstat(char *name)
{
struct stat stat;
- if (sys_newstat(name, &stat) != 0)
+ if (sys_newstat(name, &stat, 0) != 0)
return 0;
if (!S_ISBLK(stat.st_mode))
return 0;
diff --git a/init/initramfs.c b/init/initramfs.c
index d28c109..4b12040 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -245,7 +245,7 @@ static void __init clean_path(char *path
{
struct stat st;
- if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) {
+ if (!sys_newlstat(path, &st, 0) && (st.st_mode^mode) & S_IFMT) {
if (S_ISDIR(st.st_mode))
sys_rmdir(path);
else
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [patch] add flags to stat()
2006-08-06 15:58 [patch] add flags to stat() Ameer Armaly
@ 2006-08-07 7:11 ` Josef Sipek
2006-08-07 16:48 ` Bryan Henderson
2006-08-07 14:23 ` Matthew Wilcox
1 sibling, 1 reply; 6+ messages in thread
From: Josef Sipek @ 2006-08-07 7:11 UTC (permalink / raw)
To: Ameer Armaly; +Cc: linux-fsdevel
On Sun, Aug 06, 2006 at 11:58:26AM -0400, Ameer Armaly wrote:
...
> +asmlinkage long sys_newstat(char __user *filename, struct stat __user
> *statbuf, unsigned int flags)
...
> + if(!flags) /*The want everything, so let's flip on all the flags.*/
> + --flags;
if (!flags)
flags = ~0;
or even..
flags = flags ? flags : ~0;
Alternatively, you could define S_ALL, have it include all the flags and use
that instead of ~0. This is probably the best option.
Josef "Jeff" Sipek.
--
You measure democracy by the freedom it gives its dissidents, not the
freedom it gives its assimilated conformists.
- Abbie Hoffman
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] add flags to stat()
2006-08-06 15:58 [patch] add flags to stat() Ameer Armaly
2006-08-07 7:11 ` Josef Sipek
@ 2006-08-07 14:23 ` Matthew Wilcox
1 sibling, 0 replies; 6+ messages in thread
From: Matthew Wilcox @ 2006-08-07 14:23 UTC (permalink / raw)
To: Ameer Armaly; +Cc: linux-fsdevel
On Sun, Aug 06, 2006 at 11:58:26AM -0400, Ameer Armaly wrote:
> -asmlinkage long sys_newstat(char __user *filename, struct stat __user
> *statbuf)
> +asmlinkage long sys_newstat(char __user *filename, struct stat __user
> *statbuf, unsigned int flags)
> {
> struct kstat stat;
> - int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
> + int error;
> + if(!flags) /*The want everything, so let's flip on all the flags.*/
> + --flags;
> + error = vfs_stat_fd(AT_FDCWD, filename, &stat, flags);
You can't assume that old programs calling sys_newstat will happen to
have a 0 in the flags argument. Look at how we handled this for
sys_mount (MS_MGC_VAL).
Or introduce new syscalls with flags, of course.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] add flags to stat()
2006-08-07 7:11 ` Josef Sipek
@ 2006-08-07 16:48 ` Bryan Henderson
2006-08-07 17:06 ` Dave Kleikamp
0 siblings, 1 reply; 6+ messages in thread
From: Bryan Henderson @ 2006-08-07 16:48 UTC (permalink / raw)
To: Josef Sipek; +Cc: Ameer Armaly, linux-fsdevel
>flags = flags ? flags : ~0;
Here's a little known GNU C feature that makes it even easier to read:
flags = flags ?: ~0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] add flags to stat()
2006-08-07 16:48 ` Bryan Henderson
@ 2006-08-07 17:06 ` Dave Kleikamp
2006-08-07 17:22 ` Josef Sipek
0 siblings, 1 reply; 6+ messages in thread
From: Dave Kleikamp @ 2006-08-07 17:06 UTC (permalink / raw)
To: Bryan Henderson; +Cc: Josef Sipek, Ameer Armaly, linux-fsdevel
On Mon, 2006-08-07 at 09:48 -0700, Bryan Henderson wrote:
> >flags = flags ? flags : ~0;
>
> Here's a little known GNU C feature that makes it even easier to read:
>
> flags = flags ?: ~0
I think the first one is easier to read. Probably since the second is
"little-known" and requires a bit more thought to understand.
--
David Kleikamp
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] add flags to stat()
2006-08-07 17:06 ` Dave Kleikamp
@ 2006-08-07 17:22 ` Josef Sipek
0 siblings, 0 replies; 6+ messages in thread
From: Josef Sipek @ 2006-08-07 17:22 UTC (permalink / raw)
To: Dave Kleikamp; +Cc: Bryan Henderson, Ameer Armaly, linux-fsdevel
On Mon, Aug 07, 2006 at 12:06:05PM -0500, Dave Kleikamp wrote:
> On Mon, 2006-08-07 at 09:48 -0700, Bryan Henderson wrote:
> > >flags = flags ? flags : ~0;
> >
> > Here's a little known GNU C feature that makes it even easier to read:
> >
> > flags = flags ?: ~0
Bryan: Interesting, I didn't know that.
> I think the first one is easier to read. Probably since the second is
> "little-known" and requires a bit more thought to understand.
Agreed.
Josef "Jeff" Sipek.
--
#endif /* NO LIFE */
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-08-07 17:23 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-06 15:58 [patch] add flags to stat() Ameer Armaly
2006-08-07 7:11 ` Josef Sipek
2006-08-07 16:48 ` Bryan Henderson
2006-08-07 17:06 ` Dave Kleikamp
2006-08-07 17:22 ` Josef Sipek
2006-08-07 14:23 ` Matthew Wilcox
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).