diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /fs/fat | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 |
samsung update 1
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/dir.c | 13 | ||||
-rw-r--r-- | fs/fat/fat.h | 1 | ||||
-rw-r--r-- | fs/fat/file.c | 59 | ||||
-rw-r--r-- | fs/fat/inode.c | 74 |
4 files changed, 145 insertions, 2 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 4ad6473..44c9260 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -98,7 +98,7 @@ next: *bh = sb_bread(sb, phys); if (*bh == NULL) { - fat_msg(sb, KERN_ERR, "Directory bread(block %llu) failed", + fat_msg(sb, KERN_INFO, "Directory bread(block %llu) failed", (llu)phys); /* skip this block */ *pos = (iblock + 1) << sb->s_blocksize_bits; @@ -754,6 +754,13 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp, return ret; } +static int fat_ioctl_volume_id(struct inode *dir) +{ + struct super_block *sb = dir->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); + return sbi->vol_id; +} + static long fat_dir_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -770,6 +777,8 @@ static long fat_dir_ioctl(struct file *filp, unsigned int cmd, short_only = 0; both = 1; break; + case VFAT_IOCTL_GET_VOLUME_ID: + return fat_ioctl_volume_id(inode); default: return fat_generic_ioctl(filp, cmd, arg); } @@ -1231,7 +1240,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, struct super_block *sb = dir->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */ - struct msdos_dir_entry *de; + struct msdos_dir_entry *de = NULL; int err, free_slots, i, nr_bhs; loff_t pos, i_pos; diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 8276cc2..74fe5d3 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -78,6 +78,7 @@ struct msdos_sb_info { const void *dir_ops; /* Opaque; default directory operations */ int dir_per_block; /* dir entries per block */ int dir_per_block_bits; /* log2(dir_per_block) */ + unsigned long vol_id; /* volume ID */ int fatent_shift; struct fatent_operations *fatent_ops; diff --git a/fs/fat/file.c b/fs/fat/file.c index 7018e1d..7279b96 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -17,6 +17,7 @@ #include <linux/blkdev.h> #include <linux/fsnotify.h> #include <linux/security.h> +#include <linux/namei.h> #include "fat.h" static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) @@ -115,6 +116,62 @@ out: return err; } +extern int _fat_fallocate(struct inode *inode, loff_t len); + +static long fat_vmw_extend(struct file *filp, unsigned long len) +{ + struct inode *inode = filp->f_path.dentry->d_inode; + loff_t off = len; + const char mvpEnabledPath[] = "/data/data/com.vmware.mvp.enabled"; + struct path path; + struct kstat stat; + int err; + + /* + * Perform some sanity checks (from do_fallocate) + */ + + if (len <= 0) { + return -EINVAL; + } + + if (!(filp->f_mode & FMODE_WRITE)) { + return -EBADF; + } + + /* + * Revalidate the write permissions, in case security policy has + * changed since the files were opened. + */ + err = security_file_permission(filp, MAY_WRITE); + if (err) { + return err; + } + + /* + * Verify caller process belongs to mvp. + */ + + err = kern_path(mvpEnabledPath, 0, &path); + if (err) { + return err; + } + + err = vfs_getattr(path.mnt, path.dentry, &stat); + if (err) { + return err; + } + + if (current_euid() != stat.uid && current_euid() != 0) { + return -EPERM; + } + + /* + * Every thing is clear, let's allocate space. + */ + return _fat_fallocate(inode, off); +} + long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = filp->f_path.dentry->d_inode; @@ -125,6 +182,8 @@ long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return fat_ioctl_get_attributes(inode, user_attr); case FAT_IOCTL_SET_ATTRIBUTES: return fat_ioctl_set_attributes(filp, user_attr); + case FAT_IOCTL_VMW_EXTEND: + return fat_vmw_extend(filp, arg); default: return -ENOTTY; /* Inappropriate ioctl for device */ } diff --git a/fs/fat/inode.c b/fs/fat/inode.c index cb8d839..d7136bd 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -242,6 +242,71 @@ static const struct address_space_operations fat_aops = { .bmap = _fat_bmap }; +int _fat_fallocate(struct inode *inode, loff_t len) +{ + struct super_block *sb = inode->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); + int err; + sector_t nblocks, iblock; + unsigned short offset; + + if (!S_ISREG(inode->i_mode)) { + printk(KERN_ERR "_fat_fallocate: supported only for regular files\n"); + return -EOPNOTSUPP; + } + + if (IS_IMMUTABLE(inode)) { + return -EPERM; + } + + mutex_lock(&inode->i_mutex); + + /* file is already big enough */ + if (len <= i_size_read(inode)) { + mutex_unlock(&inode->i_mutex); + return 0; + } + + nblocks = (len + sb->s_blocksize - 1 ) >> sb->s_blocksize_bits; + iblock = (MSDOS_I(inode)->mmu_private + sb->s_blocksize - 1) >> sb->s_blocksize_bits; + + /* validate new size */ + err = inode_newsize_ok(inode, len); + if (err) { + mutex_unlock(&inode->i_mutex); + return err; + } + + /* check for available blocks on last cluster */ + offset = (unsigned long)iblock & (sbi->sec_per_clus - 1); + if (offset) { + iblock += min((unsigned long) (sbi->sec_per_clus - offset), + (unsigned long) (nblocks - iblock)); + } + + /* now allocate new clusters */ + while (iblock < nblocks) { + err = fat_add_cluster(inode); + if (err) { + break; + } + + iblock += min((unsigned long) sbi->sec_per_clus, + (unsigned long) (nblocks - iblock)); + } + + /* update inode informations */ + len = min(len, (loff_t)(iblock << sb->s_blocksize_bits)); + i_size_write(inode, len); + MSDOS_I(inode)->mmu_private = len; + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + + mutex_unlock(&inode->i_mutex); + + return err; +} + /* * New FAT inode stuff. We do the following: * a) i_ino is constant and has nothing with on-disk location. @@ -1245,6 +1310,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, struct inode *root_inode = NULL, *fat_inode = NULL; struct buffer_head *bh; struct fat_boot_sector *b; + struct fat_boot_bsx *bsx; struct msdos_sb_info *sbi; u16 logical_sector_size; u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; @@ -1390,6 +1456,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, goto out_fail; } + bsx = (struct fat_boot_bsx *)(bh->b_data + FAT32_BSX_OFFSET); + fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; if (!IS_FSINFO(fsinfo)) { fat_msg(sb, KERN_WARNING, "Invalid FSINFO signature: " @@ -1405,8 +1473,14 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, } brelse(fsinfo_bh); + } else { + bsx = (struct fat_boot_bsx *)(bh->b_data + FAT16_BSX_OFFSET); } + /* interpret volume ID as a little endian 32 bit integer */ + sbi->vol_id = (((u32)bsx->vol_id[0]) | ((u32)bsx->vol_id[1] << 8) | + ((u32)bsx->vol_id[2] << 16) | ((u32)bsx->vol_id[3] << 24)); + sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; |