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 =
truncate: EIO_ERROR,
permission: EIO_ERROR,
revalidate: EIO_ERROR,
getattr: EIO_ERROR,
};
......
......@@ -24,6 +24,7 @@ struct file_operations minix_file_operations = {
struct inode_operations minix_file_inode_operations = {
truncate: minix_truncate,
getattr: minix_getattr,
};
int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
......
......@@ -340,6 +340,12 @@ static struct address_space_operations minix_aops = {
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)
{
if (S_ISREG(inode->i_mode)) {
......@@ -351,7 +357,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev)
inode->i_fop = &minix_dir_operations;
inode->i_mapping->a_ops = &minix_aops;
} 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;
} else
init_special_inode(inode, inode->i_mode, rdev);
......@@ -518,6 +524,17 @@ int minix_sync_inode(struct inode * inode)
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.
*/
......
......@@ -345,3 +345,18 @@ static inline void truncate (struct inode * inode)
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
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)
{
truncate(inode);
}
unsigned V1_minix_blocks(loff_t size)
{
return nblocks(size);
}
......@@ -58,3 +58,8 @@ void V2_minix_truncate(struct inode * 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);
extern void minix_free_block(struct inode * inode, int block);
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 V2_minix_truncate(struct inode *);
extern void minix_truncate(struct inode *);
......@@ -62,6 +65,8 @@ extern int minix_sync_inode(struct inode *);
extern void minix_set_inode(struct inode *, dev_t);
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 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 int minix_add_link(struct dentry*, struct inode*);
......
......@@ -307,4 +307,5 @@ struct inode_operations minix_dir_inode_operations = {
rmdir: minix_rmdir,
mknod: minix_mknod,
rename: minix_rename,
getattr: minix_getattr,
};
......@@ -20,22 +20,14 @@
static __inline__ int
do_revalidate(struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate)
struct inode *inode = dentry->d_inode;
if (inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
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->ino = inode->i_ino;
stat->mode = inode->i_mode;
......@@ -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->size = inode->i_size;
/*
* st_blocks and st_blksize are approximated with a simple algorithm if
* 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.
*/
stat->blocks = inode->i_blocks;
stat->blksize = inode->i_blksize;
}
/*
* 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.
* Everything is in units of BLOCK_SIZE until the assignment to
* tmp.st_blksize.
*/
#define D_B 7
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
if (!inode->i_blksize) {
blocks = (stat->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
if (blocks > D_B) {
indirect = (blocks - D_B + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1) {
indirect = (indirect - 1 + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1)
blocks++;
}
}
stat->blocks = (BLOCK_SIZE / 512) * blocks;
stat->blksize = BLOCK_SIZE;
} else {
stat->blocks = inode->i_blocks;
stat->blksize = inode->i_blksize;
static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
int res = 0;
struct inode *inode = dentry->d_inode;
if (inode->i_op->getattr)
return inode->i_op->getattr(mnt, dentry, stat);
res = do_revalidate(dentry);
if (res)
return res;
generic_fillattr(inode, stat);
if (!stat->blksize) {
struct super_block *s = inode->i_sb;
unsigned blocks;
blocks = (stat->size+s->s_blocksize-1) >> s->s_blocksize_bits;
stat->blocks = (s->s_blocksize / 512) * blocks;
stat->blksize = s->s_blocksize;
}
return 0;
}
......
......@@ -29,6 +29,7 @@ struct file_operations sysv_file_operations = {
struct inode_operations sysv_file_inode_operations = {
truncate: sysv_truncate,
getattr: sysv_getattr,
};
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,
static struct inode_operations sysv_symlink_inode_operations = {
readlink: page_readlink,
follow_link: page_follow_link,
getattr: sysv_getattr,
};
void sysv_set_inode(struct inode *inode, dev_t rdev)
......
......@@ -422,6 +422,30 @@ void sysv_truncate (struct inode * 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)
{
return block_write_full_page(page,get_block);
......
......@@ -317,4 +317,5 @@ struct inode_operations sysv_dir_inode_operations = {
rmdir: sysv_rmdir,
mknod: sysv_mknod,
rename: sysv_rename,
getattr: sysv_getattr,
};
......@@ -137,6 +137,7 @@ extern void sysv_write_inode(struct inode *, int);
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *, int);
extern void sysv_set_inode(struct inode *, dev_t);
extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *);
/* dir.c */
extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **);
......
......@@ -783,7 +783,7 @@ struct inode_operations {
int (*permission) (struct inode *, int);
int (*revalidate) (struct dentry *);
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);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
......@@ -1283,6 +1283,7 @@ extern int vfs_follow_link(struct nameidata *, const char *);
extern int page_readlink(struct dentry *, char *, int);
extern int page_follow_link(struct dentry *, struct nameidata *);
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 *);
......
......@@ -258,6 +258,7 @@ EXPORT_SYMBOL(vfs_lstat);
EXPORT_SYMBOL(lock_rename);
EXPORT_SYMBOL(unlock_rename);
EXPORT_SYMBOL(generic_read_dir);
EXPORT_SYMBOL(generic_fillattr);
EXPORT_SYMBOL(generic_file_llseek);
EXPORT_SYMBOL(remote_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