aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /fs/fat
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_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.c13
-rw-r--r--fs/fat/fat.h1
-rw-r--r--fs/fat/file.c59
-rw-r--r--fs/fat/inode.c74
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;