Commit 1d13173b authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] add proper ->getattr()

 add proper ->getattr(), clean up do_getattr() and friends.
parent d8814650
...@@ -61,6 +61,7 @@ struct inode_operations bad_inode_ops = ...@@ -61,6 +61,7 @@ struct inode_operations bad_inode_ops =
truncate: EIO_ERROR, truncate: EIO_ERROR,
permission: EIO_ERROR, permission: EIO_ERROR,
revalidate: EIO_ERROR, revalidate: EIO_ERROR,
getattr: EIO_ERROR,
}; };
......
...@@ -24,6 +24,7 @@ struct file_operations minix_file_operations = { ...@@ -24,6 +24,7 @@ struct file_operations minix_file_operations = {
struct inode_operations minix_file_inode_operations = { struct inode_operations minix_file_inode_operations = {
truncate: minix_truncate, truncate: minix_truncate,
getattr: minix_getattr,
}; };
int minix_sync_file(struct file * file, struct dentry *dentry, int datasync) int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
......
...@@ -340,6 +340,12 @@ static struct address_space_operations minix_aops = { ...@@ -340,6 +340,12 @@ static struct address_space_operations minix_aops = {
bmap: minix_bmap bmap: minix_bmap
}; };
static struct inode_operations minix_symlink_inode_operations = {
readlink: page_readlink,
follow_link: page_follow_link,
getattr: minix_getattr,
};
void minix_set_inode(struct inode *inode, dev_t rdev) void minix_set_inode(struct inode *inode, dev_t rdev)
{ {
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
...@@ -351,7 +357,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev) ...@@ -351,7 +357,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev)
inode->i_fop = &minix_dir_operations; inode->i_fop = &minix_dir_operations;
inode->i_mapping->a_ops = &minix_aops; inode->i_mapping->a_ops = &minix_aops;
} else if (S_ISLNK(inode->i_mode)) { } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations; inode->i_op = &minix_symlink_inode_operations;
inode->i_mapping->a_ops = &minix_aops; inode->i_mapping->a_ops = &minix_aops;
} else } else
init_special_inode(inode, inode->i_mode, rdev); init_special_inode(inode, inode->i_mode, rdev);
...@@ -518,6 +524,17 @@ int minix_sync_inode(struct inode * inode) ...@@ -518,6 +524,17 @@ int minix_sync_inode(struct inode * inode)
return err; return err;
} }
int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
generic_fillattr(dentry->d_inode, stat);
if (INODE_VERSION(dentry->d_inode) == MINIX_V1)
stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size);
else
stat->blocks = (BLOCK_SIZE / 512) * V2_minix_blocks(stat->size);
stat->blksize = BLOCK_SIZE;
return 0;
}
/* /*
* The function that is called for file truncation. * The function that is called for file truncation.
*/ */
......
...@@ -345,3 +345,18 @@ static inline void truncate (struct inode * inode) ...@@ -345,3 +345,18 @@ static inline void truncate (struct inode * inode)
inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
static inline unsigned nblocks(loff_t size)
{
unsigned blocks, res, direct = DIRECT, i = DEPTH;
blocks = (size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
res = blocks;
while (--i && blocks > direct) {
blocks -= direct;
blocks += BLOCK_SIZE/sizeof(block_t) - 1;
blocks /= BLOCK_SIZE/sizeof(block_t);
res += blocks;
direct = 1;
}
return blocks;
}
...@@ -53,3 +53,8 @@ void V1_minix_truncate(struct inode * inode) ...@@ -53,3 +53,8 @@ void V1_minix_truncate(struct inode * inode)
{ {
truncate(inode); truncate(inode);
} }
unsigned V1_minix_blocks(loff_t size)
{
return nblocks(size);
}
...@@ -58,3 +58,8 @@ void V2_minix_truncate(struct inode * inode) ...@@ -58,3 +58,8 @@ void V2_minix_truncate(struct inode * inode)
{ {
truncate(inode); truncate(inode);
} }
unsigned V2_minix_blocks(loff_t size)
{
return nblocks(size);
}
...@@ -55,6 +55,9 @@ extern int minix_new_block(struct inode * inode); ...@@ -55,6 +55,9 @@ extern int minix_new_block(struct inode * inode);
extern void minix_free_block(struct inode * inode, int block); extern void minix_free_block(struct inode * inode, int block);
extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern void V2_minix_truncate(struct inode *);
extern void V1_minix_truncate(struct inode *); extern void V1_minix_truncate(struct inode *);
extern void V2_minix_truncate(struct inode *); extern void V2_minix_truncate(struct inode *);
extern void minix_truncate(struct inode *); extern void minix_truncate(struct inode *);
...@@ -62,6 +65,8 @@ extern int minix_sync_inode(struct inode *); ...@@ -62,6 +65,8 @@ extern int minix_sync_inode(struct inode *);
extern void minix_set_inode(struct inode *, dev_t); extern void minix_set_inode(struct inode *, dev_t);
extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
extern unsigned V1_minix_blocks(loff_t);
extern unsigned V2_minix_blocks(loff_t);
extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**); extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
extern int minix_add_link(struct dentry*, struct inode*); extern int minix_add_link(struct dentry*, struct inode*);
......
...@@ -307,4 +307,5 @@ struct inode_operations minix_dir_inode_operations = { ...@@ -307,4 +307,5 @@ struct inode_operations minix_dir_inode_operations = {
rmdir: minix_rmdir, rmdir: minix_rmdir,
mknod: minix_mknod, mknod: minix_mknod,
rename: minix_rename, rename: minix_rename,
getattr: minix_getattr,
}; };
...@@ -20,22 +20,14 @@ ...@@ -20,22 +20,14 @@
static __inline__ int static __inline__ int
do_revalidate(struct dentry *dentry) do_revalidate(struct dentry *dentry)
{ {
struct inode * inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate) if (inode->i_op->revalidate)
return inode->i_op->revalidate(dentry); return inode->i_op->revalidate(dentry);
return 0; return 0;
} }
static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) void generic_fillattr(struct inode *inode, struct kstat *stat)
{ {
int res = 0;
unsigned int blocks, indirect;
struct inode *inode = dentry->d_inode;
res = do_revalidate(dentry);
if (res)
return res;
stat->dev = kdev_t_to_nr(inode->i_dev); stat->dev = kdev_t_to_nr(inode->i_dev);
stat->ino = inode->i_ino; stat->ino = inode->i_ino;
stat->mode = inode->i_mode; stat->mode = inode->i_mode;
...@@ -48,41 +40,29 @@ static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat ...@@ -48,41 +40,29 @@ static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
stat->ctime = inode->i_ctime; stat->ctime = inode->i_ctime;
stat->ctime = inode->i_ctime; stat->ctime = inode->i_ctime;
stat->size = inode->i_size; stat->size = inode->i_size;
/* stat->blocks = inode->i_blocks;
* st_blocks and st_blksize are approximated with a simple algorithm if stat->blksize = inode->i_blksize;
* they aren't supported directly by the filesystem. The minix and msdos }
* filesystems don't keep track of blocks, so they would either have to
* be counted explicitly (by delving into the file itself), or by using
* this simple algorithm to get a reasonable (although not 100% accurate)
* value.
*/
/* static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
* Use minix fs values for the number of direct and indirect blocks. The {
* count is now exact for the minix fs except that it counts zero blocks. int res = 0;
* Everything is in units of BLOCK_SIZE until the assignment to struct inode *inode = dentry->d_inode;
* tmp.st_blksize.
*/ if (inode->i_op->getattr)
#define D_B 7 return inode->i_op->getattr(mnt, dentry, stat);
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
res = do_revalidate(dentry);
if (!inode->i_blksize) { if (res)
blocks = (stat->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; return res;
if (blocks > D_B) {
indirect = (blocks - D_B + I_B - 1) / I_B; generic_fillattr(inode, stat);
blocks += indirect; if (!stat->blksize) {
if (indirect > 1) { struct super_block *s = inode->i_sb;
indirect = (indirect - 1 + I_B - 1) / I_B; unsigned blocks;
blocks += indirect; blocks = (stat->size+s->s_blocksize-1) >> s->s_blocksize_bits;
if (indirect > 1) stat->blocks = (s->s_blocksize / 512) * blocks;
blocks++; stat->blksize = s->s_blocksize;
}
}
stat->blocks = (BLOCK_SIZE / 512) * blocks;
stat->blksize = BLOCK_SIZE;
} else {
stat->blocks = inode->i_blocks;
stat->blksize = inode->i_blksize;
} }
return 0; return 0;
} }
......
...@@ -29,6 +29,7 @@ struct file_operations sysv_file_operations = { ...@@ -29,6 +29,7 @@ struct file_operations sysv_file_operations = {
struct inode_operations sysv_file_inode_operations = { struct inode_operations sysv_file_inode_operations = {
truncate: sysv_truncate, truncate: sysv_truncate,
getattr: sysv_getattr,
}; };
int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync) int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync)
......
...@@ -132,6 +132,7 @@ static inline void write3byte(struct sysv_sb_info *sbi, ...@@ -132,6 +132,7 @@ static inline void write3byte(struct sysv_sb_info *sbi,
static struct inode_operations sysv_symlink_inode_operations = { static struct inode_operations sysv_symlink_inode_operations = {
readlink: page_readlink, readlink: page_readlink,
follow_link: page_follow_link, follow_link: page_follow_link,
getattr: sysv_getattr,
}; };
void sysv_set_inode(struct inode *inode, dev_t rdev) void sysv_set_inode(struct inode *inode, dev_t rdev)
......
...@@ -422,6 +422,30 @@ void sysv_truncate (struct inode * inode) ...@@ -422,6 +422,30 @@ void sysv_truncate (struct inode * inode)
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
static unsigned sysv_nblocks(struct super_block *s, loff_t size)
{
struct sysv_sb_info *sbi = SYSV_SB(s);
int ptrs_bits = sbi->s_ind_per_block_bits;
unsigned blocks, res, direct = DIRECT, i = DEPTH;
blocks = (size + s->s_blocksize - 1) >> s->s_blocksize_bits;
res = blocks;
while (--i && blocks > direct) {
blocks = ((blocks - direct - 1) >> ptrs_bits) + 1;
res += blocks;
direct = 1;
}
return blocks;
}
int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
struct super_block *s = mnt->mnt_sb;
generic_fillattr(dentry->d_inode, stat);
stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size);
stat->blksize = s->s_blocksize;
return 0;
}
static int sysv_writepage(struct page *page) static int sysv_writepage(struct page *page)
{ {
return block_write_full_page(page,get_block); return block_write_full_page(page,get_block);
......
...@@ -317,4 +317,5 @@ struct inode_operations sysv_dir_inode_operations = { ...@@ -317,4 +317,5 @@ struct inode_operations sysv_dir_inode_operations = {
rmdir: sysv_rmdir, rmdir: sysv_rmdir,
mknod: sysv_mknod, mknod: sysv_mknod,
rename: sysv_rename, rename: sysv_rename,
getattr: sysv_getattr,
}; };
...@@ -137,6 +137,7 @@ extern void sysv_write_inode(struct inode *, int); ...@@ -137,6 +137,7 @@ extern void sysv_write_inode(struct inode *, int);
extern int sysv_sync_inode(struct inode *); extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *, int); extern int sysv_sync_file(struct file *, struct dentry *, int);
extern void sysv_set_inode(struct inode *, dev_t); extern void sysv_set_inode(struct inode *, dev_t);
extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *);
/* dir.c */ /* dir.c */
extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **); extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **);
......
...@@ -783,7 +783,7 @@ struct inode_operations { ...@@ -783,7 +783,7 @@ struct inode_operations {
int (*permission) (struct inode *, int); int (*permission) (struct inode *, int);
int (*revalidate) (struct dentry *); int (*revalidate) (struct dentry *);
int (*setattr) (struct dentry *, struct iattr *); int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *, void *, size_t, int); int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t); ssize_t (*listxattr) (struct dentry *, char *, size_t);
...@@ -1283,6 +1283,7 @@ extern int vfs_follow_link(struct nameidata *, const char *); ...@@ -1283,6 +1283,7 @@ extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int); extern int page_readlink(struct dentry *, char *, int);
extern int page_follow_link(struct dentry *, struct nameidata *); extern int page_follow_link(struct dentry *, struct nameidata *);
extern struct inode_operations page_symlink_inode_operations; extern struct inode_operations page_symlink_inode_operations;
extern void generic_fillattr(struct inode *, struct kstat *);
extern int vfs_readdir(struct file *, filldir_t, void *); extern int vfs_readdir(struct file *, filldir_t, void *);
......
...@@ -258,6 +258,7 @@ EXPORT_SYMBOL(vfs_lstat); ...@@ -258,6 +258,7 @@ EXPORT_SYMBOL(vfs_lstat);
EXPORT_SYMBOL(lock_rename); EXPORT_SYMBOL(lock_rename);
EXPORT_SYMBOL(unlock_rename); EXPORT_SYMBOL(unlock_rename);
EXPORT_SYMBOL(generic_read_dir); EXPORT_SYMBOL(generic_read_dir);
EXPORT_SYMBOL(generic_fillattr);
EXPORT_SYMBOL(generic_file_llseek); EXPORT_SYMBOL(generic_file_llseek);
EXPORT_SYMBOL(remote_llseek); EXPORT_SYMBOL(remote_llseek);
EXPORT_SYMBOL(no_llseek); EXPORT_SYMBOL(no_llseek);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment