Merge branch 'akpm' (patches from Andrew)
Merge third patch-bomb from Andrew Morton: "I'm pretty much done for -rc1 now: - the rest of MM, basically - lib/ updates - checkpatch, epoll, hfs, fatfs, ptrace, coredump, exit - cpu_mask simplifications - kexec, rapidio, MAINTAINERS etc, etc. - more dma-mapping cleanups/simplifications from hch" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (109 commits) MAINTAINERS: add/fix git URLs for various subsystems mm: memcontrol: add "sock" to cgroup2 memory.stat mm: memcontrol: basic memory statistics in cgroup2 memory controller mm: memcontrol: do not uncharge old page in page cache replacement Documentation: cgroup: add memory.swap.{current,max} description mm: free swap cache aggressively if memcg swap is full mm: vmscan: do not scan anon pages if memcg swap limit is hit swap.h: move memcg related stuff to the end of the file mm: memcontrol: replace mem_cgroup_lruvec_online with mem_cgroup_online mm: vmscan: pass memcg to get_scan_count() mm: memcontrol: charge swap to cgroup2 mm: memcontrol: clean up alloc, online, offline, free functions mm: memcontrol: flatten struct cg_proto mm: memcontrol: rein in the CONFIG space madness net: drop tcp_memcontrol.c mm: memcontrol: introduce CONFIG_MEMCG_LEGACY_KMEM mm: memcontrol: allow to disable kmem accounting for cgroup2 mm: memcontrol: account "kmem" consumers in cgroup2 memory controller mm: memcontrol: move kmem accounting code to CONFIG_MEMCG mm: memcontrol: separate kmem code from legacy tcp accounting code ...
This commit is contained in:
@@ -44,24 +44,24 @@ struct adfs_dir_ops;
|
||||
*/
|
||||
struct adfs_sb_info {
|
||||
union { struct {
|
||||
struct adfs_discmap *s_map; /* bh list containing map */
|
||||
const struct adfs_dir_ops *s_dir; /* directory operations */
|
||||
struct adfs_discmap *s_map; /* bh list containing map */
|
||||
const struct adfs_dir_ops *s_dir; /* directory operations */
|
||||
};
|
||||
struct rcu_head rcu; /* used only at shutdown time */
|
||||
struct rcu_head rcu; /* used only at shutdown time */
|
||||
};
|
||||
kuid_t s_uid; /* owner uid */
|
||||
kgid_t s_gid; /* owner gid */
|
||||
umode_t s_owner_mask; /* ADFS owner perm -> unix perm */
|
||||
umode_t s_other_mask; /* ADFS other perm -> unix perm */
|
||||
kuid_t s_uid; /* owner uid */
|
||||
kgid_t s_gid; /* owner gid */
|
||||
umode_t s_owner_mask; /* ADFS owner perm -> unix perm */
|
||||
umode_t s_other_mask; /* ADFS other perm -> unix perm */
|
||||
int s_ftsuffix; /* ,xyz hex filetype suffix option */
|
||||
|
||||
__u32 s_ids_per_zone; /* max. no ids in one zone */
|
||||
__u32 s_idlen; /* length of ID in map */
|
||||
__u32 s_map_size; /* sector size of a map */
|
||||
unsigned long s_size; /* total size (in blocks) of this fs */
|
||||
signed int s_map2blk; /* shift left by this for map->sector */
|
||||
unsigned int s_log2sharesize;/* log2 share size */
|
||||
__le32 s_version; /* disc format version */
|
||||
__u32 s_ids_per_zone; /* max. no ids in one zone */
|
||||
__u32 s_idlen; /* length of ID in map */
|
||||
__u32 s_map_size; /* sector size of a map */
|
||||
unsigned long s_size; /* total size (in blocks) of this fs */
|
||||
signed int s_map2blk; /* shift left by this for map->sector*/
|
||||
unsigned int s_log2sharesize;/* log2 share size */
|
||||
__le32 s_version; /* disc format version */
|
||||
unsigned int s_namelen; /* maximum number of characters in name */
|
||||
};
|
||||
|
||||
|
@@ -118,6 +118,26 @@ int cn_esc_printf(struct core_name *cn, const char *fmt, ...)
|
||||
ret = cn_vprintf(cn, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Ensure that this coredump name component can't cause the
|
||||
* resulting corefile path to consist of a ".." or ".".
|
||||
*/
|
||||
if ((cn->used - cur == 1 && cn->corename[cur] == '.') ||
|
||||
(cn->used - cur == 2 && cn->corename[cur] == '.'
|
||||
&& cn->corename[cur+1] == '.'))
|
||||
cn->corename[cur] = '!';
|
||||
|
||||
/*
|
||||
* Empty names are fishy and could be used to create a "//" in a
|
||||
* corefile name, causing the coredump to happen one directory
|
||||
* level too high. Enforce that all components of the core
|
||||
* pattern are at least one character long.
|
||||
*/
|
||||
if (cn->used == cur)
|
||||
ret = cn_printf(cn, "!");
|
||||
}
|
||||
|
||||
for (; cur < cn->used; ++cur) {
|
||||
if (cn->corename[cur] == '/')
|
||||
cn->corename[cur] = '!';
|
||||
|
@@ -92,7 +92,7 @@
|
||||
*/
|
||||
|
||||
/* Epoll private bits inside the event mask */
|
||||
#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET)
|
||||
#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE)
|
||||
|
||||
/* Maximum number of nesting allowed inside epoll sets */
|
||||
#define EP_MAX_NESTS 4
|
||||
@@ -1002,6 +1002,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
|
||||
unsigned long flags;
|
||||
struct epitem *epi = ep_item_from_wait(wait);
|
||||
struct eventpoll *ep = epi->ep;
|
||||
int ewake = 0;
|
||||
|
||||
if ((unsigned long)key & POLLFREE) {
|
||||
ep_pwq_from_wait(wait)->whead = NULL;
|
||||
@@ -1066,8 +1067,10 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
|
||||
* Wake up ( if active ) both the eventpoll wait list and the ->poll()
|
||||
* wait list.
|
||||
*/
|
||||
if (waitqueue_active(&ep->wq))
|
||||
if (waitqueue_active(&ep->wq)) {
|
||||
ewake = 1;
|
||||
wake_up_locked(&ep->wq);
|
||||
}
|
||||
if (waitqueue_active(&ep->poll_wait))
|
||||
pwake++;
|
||||
|
||||
@@ -1078,6 +1081,9 @@ out_unlock:
|
||||
if (pwake)
|
||||
ep_poll_safewake(&ep->poll_wait);
|
||||
|
||||
if (epi->event.events & EPOLLEXCLUSIVE)
|
||||
return ewake;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1095,7 +1101,10 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
|
||||
init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);
|
||||
pwq->whead = whead;
|
||||
pwq->base = epi;
|
||||
add_wait_queue(whead, &pwq->wait);
|
||||
if (epi->event.events & EPOLLEXCLUSIVE)
|
||||
add_wait_queue_exclusive(whead, &pwq->wait);
|
||||
else
|
||||
add_wait_queue(whead, &pwq->wait);
|
||||
list_add_tail(&pwq->llink, &epi->pwqlist);
|
||||
epi->nwait++;
|
||||
} else {
|
||||
@@ -1861,6 +1870,15 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
|
||||
if (f.file == tf.file || !is_file_epoll(f.file))
|
||||
goto error_tgt_fput;
|
||||
|
||||
/*
|
||||
* epoll adds to the wakeup queue at EPOLL_CTL_ADD time only,
|
||||
* so EPOLLEXCLUSIVE is not allowed for a EPOLL_CTL_MOD operation.
|
||||
* Also, we do not currently supported nested exclusive wakeups.
|
||||
*/
|
||||
if ((epds.events & EPOLLEXCLUSIVE) && (op == EPOLL_CTL_MOD ||
|
||||
(op == EPOLL_CTL_ADD && is_file_epoll(tf.file))))
|
||||
goto error_tgt_fput;
|
||||
|
||||
/*
|
||||
* At this point it is safe to assume that the "private_data" contains
|
||||
* our own data structure.
|
||||
|
@@ -301,15 +301,59 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
|
||||
return dclus;
|
||||
}
|
||||
|
||||
int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
|
||||
unsigned long *mapped_blocks, int create)
|
||||
int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
|
||||
sector_t last_block,
|
||||
unsigned long *mapped_blocks, sector_t *bmap)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
int cluster, offset;
|
||||
|
||||
cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
|
||||
offset = sector & (sbi->sec_per_clus - 1);
|
||||
cluster = fat_bmap_cluster(inode, cluster);
|
||||
if (cluster < 0)
|
||||
return cluster;
|
||||
else if (cluster) {
|
||||
*bmap = fat_clus_to_blknr(sbi, cluster) + offset;
|
||||
*mapped_blocks = sbi->sec_per_clus - offset;
|
||||
if (*mapped_blocks > last_block - sector)
|
||||
*mapped_blocks = last_block - sector;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_exceed_eof(struct inode *inode, sector_t sector,
|
||||
sector_t *last_block, int create)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
const unsigned long blocksize = sb->s_blocksize;
|
||||
const unsigned char blocksize_bits = sb->s_blocksize_bits;
|
||||
|
||||
*last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
|
||||
if (sector >= *last_block) {
|
||||
if (!create)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* ->mmu_private can access on only allocation path.
|
||||
* (caller must hold ->i_mutex)
|
||||
*/
|
||||
*last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
|
||||
>> blocksize_bits;
|
||||
if (sector >= *last_block)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
|
||||
unsigned long *mapped_blocks, int create, bool from_bmap)
|
||||
{
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
|
||||
sector_t last_block;
|
||||
int cluster, offset;
|
||||
|
||||
*phys = 0;
|
||||
*mapped_blocks = 0;
|
||||
@@ -321,31 +365,16 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
|
||||
return 0;
|
||||
}
|
||||
|
||||
last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
|
||||
if (sector >= last_block) {
|
||||
if (!create)
|
||||
if (!from_bmap) {
|
||||
if (is_exceed_eof(inode, sector, &last_block, create))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* ->mmu_private can access on only allocation path.
|
||||
* (caller must hold ->i_mutex)
|
||||
*/
|
||||
last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
|
||||
>> blocksize_bits;
|
||||
} else {
|
||||
last_block = inode->i_blocks >>
|
||||
(inode->i_sb->s_blocksize_bits - 9);
|
||||
if (sector >= last_block)
|
||||
return 0;
|
||||
}
|
||||
|
||||
cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
|
||||
offset = sector & (sbi->sec_per_clus - 1);
|
||||
cluster = fat_bmap_cluster(inode, cluster);
|
||||
if (cluster < 0)
|
||||
return cluster;
|
||||
else if (cluster) {
|
||||
*phys = fat_clus_to_blknr(sbi, cluster) + offset;
|
||||
*mapped_blocks = sbi->sec_per_clus - offset;
|
||||
if (*mapped_blocks > last_block - sector)
|
||||
*mapped_blocks = last_block - sector;
|
||||
}
|
||||
return 0;
|
||||
return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks,
|
||||
phys);
|
||||
}
|
||||
|
@@ -91,7 +91,7 @@ next:
|
||||
|
||||
*bh = NULL;
|
||||
iblock = *pos >> sb->s_blocksize_bits;
|
||||
err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0);
|
||||
err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0, false);
|
||||
if (err || !phys)
|
||||
return -1; /* beyond EOF or error */
|
||||
|
||||
|
@@ -87,7 +87,7 @@ struct msdos_sb_info {
|
||||
unsigned int vol_id; /*volume ID*/
|
||||
|
||||
int fatent_shift;
|
||||
struct fatent_operations *fatent_ops;
|
||||
const struct fatent_operations *fatent_ops;
|
||||
struct inode *fat_inode;
|
||||
struct inode *fsinfo_inode;
|
||||
|
||||
@@ -285,8 +285,11 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
|
||||
extern void fat_cache_inval_inode(struct inode *inode);
|
||||
extern int fat_get_cluster(struct inode *inode, int cluster,
|
||||
int *fclus, int *dclus);
|
||||
extern int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
|
||||
sector_t last_block,
|
||||
unsigned long *mapped_blocks, sector_t *bmap);
|
||||
extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
|
||||
unsigned long *mapped_blocks, int create);
|
||||
unsigned long *mapped_blocks, int create, bool from_bmap);
|
||||
|
||||
/* fat/dir.c */
|
||||
extern const struct file_operations fat_dir_operations;
|
||||
@@ -384,6 +387,7 @@ static inline unsigned long fat_dir_hash(int logstart)
|
||||
{
|
||||
return hash_32(logstart, FAT_HASH_BITS);
|
||||
}
|
||||
extern int fat_add_cluster(struct inode *inode);
|
||||
|
||||
/* fat/misc.c */
|
||||
extern __printf(3, 4) __cold
|
||||
|
@@ -99,7 +99,7 @@ err:
|
||||
static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
|
||||
int offset, sector_t blocknr)
|
||||
{
|
||||
struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
|
||||
WARN_ON(blocknr < MSDOS_SB(sb)->fat_start);
|
||||
fatent->fat_inode = MSDOS_SB(sb)->fat_inode;
|
||||
@@ -246,7 +246,7 @@ static int fat32_ent_next(struct fat_entry *fatent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fatent_operations fat12_ops = {
|
||||
static const struct fatent_operations fat12_ops = {
|
||||
.ent_blocknr = fat12_ent_blocknr,
|
||||
.ent_set_ptr = fat12_ent_set_ptr,
|
||||
.ent_bread = fat12_ent_bread,
|
||||
@@ -255,7 +255,7 @@ static struct fatent_operations fat12_ops = {
|
||||
.ent_next = fat12_ent_next,
|
||||
};
|
||||
|
||||
static struct fatent_operations fat16_ops = {
|
||||
static const struct fatent_operations fat16_ops = {
|
||||
.ent_blocknr = fat_ent_blocknr,
|
||||
.ent_set_ptr = fat16_ent_set_ptr,
|
||||
.ent_bread = fat_ent_bread,
|
||||
@@ -264,7 +264,7 @@ static struct fatent_operations fat16_ops = {
|
||||
.ent_next = fat16_ent_next,
|
||||
};
|
||||
|
||||
static struct fatent_operations fat32_ops = {
|
||||
static const struct fatent_operations fat32_ops = {
|
||||
.ent_blocknr = fat_ent_blocknr,
|
||||
.ent_set_ptr = fat32_ent_set_ptr,
|
||||
.ent_bread = fat_ent_bread,
|
||||
@@ -320,7 +320,7 @@ static inline int fat_ent_update_ptr(struct super_block *sb,
|
||||
int offset, sector_t blocknr)
|
||||
{
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
struct fatent_operations *ops = sbi->fatent_ops;
|
||||
const struct fatent_operations *ops = sbi->fatent_ops;
|
||||
struct buffer_head **bhs = fatent->bhs;
|
||||
|
||||
/* Is this fatent's blocks including this entry? */
|
||||
@@ -349,7 +349,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
|
||||
struct fatent_operations *ops = sbi->fatent_ops;
|
||||
const struct fatent_operations *ops = sbi->fatent_ops;
|
||||
int err, offset;
|
||||
sector_t blocknr;
|
||||
|
||||
@@ -407,7 +407,7 @@ int fat_ent_write(struct inode *inode, struct fat_entry *fatent,
|
||||
int new, int wait)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
int err;
|
||||
|
||||
ops->ent_put(fatent, new);
|
||||
@@ -432,7 +432,7 @@ static inline int fat_ent_next(struct msdos_sb_info *sbi,
|
||||
static inline int fat_ent_read_block(struct super_block *sb,
|
||||
struct fat_entry *fatent)
|
||||
{
|
||||
struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
sector_t blocknr;
|
||||
int offset;
|
||||
|
||||
@@ -463,7 +463,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
struct fatent_operations *ops = sbi->fatent_ops;
|
||||
const struct fatent_operations *ops = sbi->fatent_ops;
|
||||
struct fat_entry fatent, prev_ent;
|
||||
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
||||
int i, count, err, nr_bhs, idx_clus;
|
||||
@@ -551,7 +551,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
struct fatent_operations *ops = sbi->fatent_ops;
|
||||
const struct fatent_operations *ops = sbi->fatent_ops;
|
||||
struct fat_entry fatent;
|
||||
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
||||
int i, err, nr_bhs;
|
||||
@@ -636,7 +636,7 @@ EXPORT_SYMBOL_GPL(fat_free_clusters);
|
||||
static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
|
||||
unsigned long reada_blocks)
|
||||
{
|
||||
struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
|
||||
sector_t blocknr;
|
||||
int i, offset;
|
||||
|
||||
@@ -649,7 +649,7 @@ static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
|
||||
int fat_count_free_clusters(struct super_block *sb)
|
||||
{
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
struct fatent_operations *ops = sbi->fatent_ops;
|
||||
const struct fatent_operations *ops = sbi->fatent_ops;
|
||||
struct fat_entry fatent;
|
||||
unsigned long reada_blocks, reada_mask, cur_block;
|
||||
int err = 0, free;
|
||||
|
@@ -14,8 +14,12 @@
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/falloc.h>
|
||||
#include "fat.h"
|
||||
|
||||
static long fat_fallocate(struct file *file, int mode,
|
||||
loff_t offset, loff_t len);
|
||||
|
||||
static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
|
||||
{
|
||||
u32 attr;
|
||||
@@ -177,6 +181,7 @@ const struct file_operations fat_file_operations = {
|
||||
#endif
|
||||
.fsync = fat_file_fsync,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.fallocate = fat_fallocate,
|
||||
};
|
||||
|
||||
static int fat_cont_expand(struct inode *inode, loff_t size)
|
||||
@@ -215,6 +220,62 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preallocate space for a file. This implements fat's fallocate file
|
||||
* operation, which gets called from sys_fallocate system call. User
|
||||
* space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set
|
||||
* we just allocate clusters without zeroing them out. Otherwise we
|
||||
* allocate and zero out clusters via an expanding truncate.
|
||||
*/
|
||||
static long fat_fallocate(struct file *file, int mode,
|
||||
loff_t offset, loff_t len)
|
||||
{
|
||||
int nr_cluster; /* Number of clusters to be allocated */
|
||||
loff_t mm_bytes; /* Number of bytes to be allocated for file */
|
||||
loff_t ondisksize; /* block aligned on-disk size in bytes*/
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
int err = 0;
|
||||
|
||||
/* No support for hole punch or other fallocate flags. */
|
||||
if (mode & ~FALLOC_FL_KEEP_SIZE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* No support for dir */
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
if (mode & FALLOC_FL_KEEP_SIZE) {
|
||||
ondisksize = inode->i_blocks << 9;
|
||||
if ((offset + len) <= ondisksize)
|
||||
goto error;
|
||||
|
||||
/* First compute the number of clusters to be allocated */
|
||||
mm_bytes = offset + len - ondisksize;
|
||||
nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >>
|
||||
sbi->cluster_bits;
|
||||
|
||||
/* Start the allocation.We are not zeroing out the clusters */
|
||||
while (nr_cluster-- > 0) {
|
||||
err = fat_add_cluster(inode);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if ((offset + len) <= i_size_read(inode))
|
||||
goto error;
|
||||
|
||||
/* This is just an expanding truncate */
|
||||
err = fat_cont_expand(inode, (offset + len));
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Free all clusters after the skip'th cluster. */
|
||||
static int fat_free(struct inode *inode, int skip)
|
||||
{
|
||||
|
104
fs/fat/inode.c
104
fs/fat/inode.c
@@ -93,7 +93,7 @@ static struct fat_floppy_defaults {
|
||||
},
|
||||
};
|
||||
|
||||
static int fat_add_cluster(struct inode *inode)
|
||||
int fat_add_cluster(struct inode *inode)
|
||||
{
|
||||
int err, cluster;
|
||||
|
||||
@@ -115,10 +115,10 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
unsigned long mapped_blocks;
|
||||
sector_t phys;
|
||||
sector_t phys, last_block;
|
||||
int err, offset;
|
||||
|
||||
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
|
||||
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
|
||||
if (err)
|
||||
return err;
|
||||
if (phys) {
|
||||
@@ -135,8 +135,14 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
last_block = inode->i_blocks >> (sb->s_blocksize_bits - 9);
|
||||
offset = (unsigned long)iblock & (sbi->sec_per_clus - 1);
|
||||
if (!offset) {
|
||||
/*
|
||||
* allocate a cluster according to the following.
|
||||
* 1) no more available blocks
|
||||
* 2) not part of fallocate region
|
||||
*/
|
||||
if (!offset && !(iblock < last_block)) {
|
||||
/* TODO: multiple cluster allocation would be desirable. */
|
||||
err = fat_add_cluster(inode);
|
||||
if (err)
|
||||
@@ -148,7 +154,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
|
||||
*max_blocks = min(mapped_blocks, *max_blocks);
|
||||
MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
|
||||
|
||||
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
|
||||
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -273,13 +279,38 @@ static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fat_get_block_bmap(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
|
||||
int err;
|
||||
sector_t bmap;
|
||||
unsigned long mapped_blocks;
|
||||
|
||||
BUG_ON(create != 0);
|
||||
|
||||
err = fat_bmap(inode, iblock, &bmap, &mapped_blocks, create, true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (bmap) {
|
||||
map_bh(bh_result, sb, bmap);
|
||||
max_blocks = min(mapped_blocks, max_blocks);
|
||||
}
|
||||
|
||||
bh_result->b_size = max_blocks << sb->s_blocksize_bits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
|
||||
{
|
||||
sector_t blocknr;
|
||||
|
||||
/* fat_get_cluster() assumes the requested blocknr isn't truncated. */
|
||||
down_read(&MSDOS_I(mapping->host)->truncate_lock);
|
||||
blocknr = generic_block_bmap(mapping, block, fat_get_block);
|
||||
blocknr = generic_block_bmap(mapping, block, fat_get_block_bmap);
|
||||
up_read(&MSDOS_I(mapping->host)->truncate_lock);
|
||||
|
||||
return blocknr;
|
||||
@@ -449,6 +480,24 @@ static int fat_calc_dir_size(struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fat_validate_dir(struct inode *dir)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
|
||||
if (dir->i_nlink < 2) {
|
||||
/* Directory should have "."/".." entries at least. */
|
||||
fat_fs_error(sb, "corrupted directory (invalid entries)");
|
||||
return -EIO;
|
||||
}
|
||||
if (MSDOS_I(dir)->i_start == 0 ||
|
||||
MSDOS_I(dir)->i_start == MSDOS_SB(sb)->root_cluster) {
|
||||
/* Directory should point valid cluster. */
|
||||
fat_fs_error(sb, "corrupted directory (invalid i_start)");
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* doesn't deal with root inode */
|
||||
int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
|
||||
{
|
||||
@@ -475,6 +524,10 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
|
||||
MSDOS_I(inode)->mmu_private = inode->i_size;
|
||||
|
||||
set_nlink(inode, fat_subdirs(inode));
|
||||
|
||||
error = fat_validate_dir(inode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
} else { /* not a directory */
|
||||
inode->i_generation |= 1;
|
||||
inode->i_mode = fat_make_mode(sbi, de->attr,
|
||||
@@ -553,13 +606,43 @@ out:
|
||||
|
||||
EXPORT_SYMBOL_GPL(fat_build_inode);
|
||||
|
||||
static int __fat_write_inode(struct inode *inode, int wait);
|
||||
|
||||
static void fat_free_eofblocks(struct inode *inode)
|
||||
{
|
||||
/* Release unwritten fallocated blocks on inode eviction. */
|
||||
if ((inode->i_blocks << 9) >
|
||||
round_up(MSDOS_I(inode)->mmu_private,
|
||||
MSDOS_SB(inode->i_sb)->cluster_size)) {
|
||||
int err;
|
||||
|
||||
fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private);
|
||||
/* Fallocate results in updating the i_start/iogstart
|
||||
* for the zero byte file. So, make it return to
|
||||
* original state during evict and commit it to avoid
|
||||
* any corruption on the next access to the cluster
|
||||
* chain for the file.
|
||||
*/
|
||||
err = __fat_write_inode(inode, inode_needs_sync(inode));
|
||||
if (err) {
|
||||
fat_msg(inode->i_sb, KERN_WARNING, "Failed to "
|
||||
"update on disk inode for unused "
|
||||
"fallocated blocks, inode could be "
|
||||
"corrupted. Please run fsck");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void fat_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
if (!inode->i_nlink) {
|
||||
inode->i_size = 0;
|
||||
fat_truncate_blocks(inode, 0);
|
||||
}
|
||||
} else
|
||||
fat_free_eofblocks(inode);
|
||||
|
||||
invalidate_inode_buffers(inode);
|
||||
clear_inode(inode);
|
||||
fat_cache_inval_inode(inode);
|
||||
@@ -1146,7 +1229,12 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
|
||||
case Opt_time_offset:
|
||||
if (match_int(&args[0], &option))
|
||||
return -EINVAL;
|
||||
if (option < -12 * 60 || option > 12 * 60)
|
||||
/*
|
||||
* GMT+-12 zones may have DST corrections so at least
|
||||
* 13 hours difference is needed. Make the limit 24
|
||||
* just in case someone invents something unusual.
|
||||
*/
|
||||
if (option < -24 * 60 || option > 24 * 60)
|
||||
return -EINVAL;
|
||||
opts->tz_set = 1;
|
||||
opts->time_offset = option;
|
||||
|
@@ -214,7 +214,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
|
||||
{
|
||||
struct super_block *sb;
|
||||
struct hfs_find_data fd;
|
||||
struct list_head *pos;
|
||||
struct hfs_readdir_data *rd;
|
||||
int res, type;
|
||||
|
||||
hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
|
||||
@@ -240,9 +240,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each(pos, &HFS_I(dir)->open_dir_list) {
|
||||
struct hfs_readdir_data *rd =
|
||||
list_entry(pos, struct hfs_readdir_data, list);
|
||||
list_for_each_entry(rd, &HFS_I(dir)->open_dir_list, list) {
|
||||
if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
|
||||
rd->file->f_pos--;
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
@@ -395,7 +395,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
|
||||
|
||||
state = *get_task_state(task);
|
||||
vsize = eip = esp = 0;
|
||||
permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT);
|
||||
permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT);
|
||||
mm = get_task_mm(task);
|
||||
if (mm) {
|
||||
vsize = task_vsize(mm);
|
||||
|
@@ -403,7 +403,7 @@ static const struct file_operations proc_pid_cmdline_ops = {
|
||||
static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
|
||||
struct pid *pid, struct task_struct *task)
|
||||
{
|
||||
struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ);
|
||||
struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
|
||||
if (mm && !IS_ERR(mm)) {
|
||||
unsigned int nwords = 0;
|
||||
do {
|
||||
@@ -430,7 +430,8 @@ static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
|
||||
|
||||
wchan = get_wchan(task);
|
||||
|
||||
if (wchan && ptrace_may_access(task, PTRACE_MODE_READ) && !lookup_symbol_name(wchan, symname))
|
||||
if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)
|
||||
&& !lookup_symbol_name(wchan, symname))
|
||||
seq_printf(m, "%s", symname);
|
||||
else
|
||||
seq_putc(m, '0');
|
||||
@@ -444,7 +445,7 @@ static int lock_trace(struct task_struct *task)
|
||||
int err = mutex_lock_killable(&task->signal->cred_guard_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
|
||||
mutex_unlock(&task->signal->cred_guard_mutex);
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -697,7 +698,7 @@ static int proc_fd_access_allowed(struct inode *inode)
|
||||
*/
|
||||
task = get_proc_task(inode);
|
||||
if (task) {
|
||||
allowed = ptrace_may_access(task, PTRACE_MODE_READ);
|
||||
allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
|
||||
put_task_struct(task);
|
||||
}
|
||||
return allowed;
|
||||
@@ -732,7 +733,7 @@ static bool has_pid_permissions(struct pid_namespace *pid,
|
||||
return true;
|
||||
if (in_group_p(pid->pid_gid))
|
||||
return true;
|
||||
return ptrace_may_access(task, PTRACE_MODE_READ);
|
||||
return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
|
||||
}
|
||||
|
||||
|
||||
@@ -809,7 +810,7 @@ struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode)
|
||||
struct mm_struct *mm = ERR_PTR(-ESRCH);
|
||||
|
||||
if (task) {
|
||||
mm = mm_access(task, mode);
|
||||
mm = mm_access(task, mode | PTRACE_MODE_FSCREDS);
|
||||
put_task_struct(task);
|
||||
|
||||
if (!IS_ERR_OR_NULL(mm)) {
|
||||
@@ -952,6 +953,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
|
||||
unsigned long src = *ppos;
|
||||
int ret = 0;
|
||||
struct mm_struct *mm = file->private_data;
|
||||
unsigned long env_start, env_end;
|
||||
|
||||
if (!mm)
|
||||
return 0;
|
||||
@@ -963,19 +965,25 @@ static ssize_t environ_read(struct file *file, char __user *buf,
|
||||
ret = 0;
|
||||
if (!atomic_inc_not_zero(&mm->mm_users))
|
||||
goto free;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
env_start = mm->env_start;
|
||||
env_end = mm->env_end;
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
while (count > 0) {
|
||||
size_t this_len, max_len;
|
||||
int retval;
|
||||
|
||||
if (src >= (mm->env_end - mm->env_start))
|
||||
if (src >= (env_end - env_start))
|
||||
break;
|
||||
|
||||
this_len = mm->env_end - (mm->env_start + src);
|
||||
this_len = env_end - (env_start + src);
|
||||
|
||||
max_len = min_t(size_t, PAGE_SIZE, count);
|
||||
this_len = min(max_len, this_len);
|
||||
|
||||
retval = access_remote_vm(mm, (mm->env_start + src),
|
||||
retval = access_remote_vm(mm, (env_start + src),
|
||||
page, this_len, 0);
|
||||
|
||||
if (retval <= 0) {
|
||||
@@ -1860,7 +1868,7 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
if (!task)
|
||||
goto out_notask;
|
||||
|
||||
mm = mm_access(task, PTRACE_MODE_READ);
|
||||
mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
|
||||
if (IS_ERR_OR_NULL(mm))
|
||||
goto out;
|
||||
|
||||
@@ -2013,7 +2021,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
|
||||
goto out;
|
||||
|
||||
result = -EACCES;
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ))
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
|
||||
goto out_put_task;
|
||||
|
||||
result = -ENOENT;
|
||||
@@ -2066,7 +2074,7 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
|
||||
goto out;
|
||||
|
||||
ret = -EACCES;
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ))
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
|
||||
goto out_put_task;
|
||||
|
||||
ret = 0;
|
||||
@@ -2533,7 +2541,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ)) {
|
||||
if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
|
||||
result = -EACCES;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(struct dentry *dentry,
|
||||
if (!task)
|
||||
return error;
|
||||
|
||||
if (ptrace_may_access(task, PTRACE_MODE_READ)) {
|
||||
if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
|
||||
error = ns_get_path(&ns_path, task, ns_ops);
|
||||
if (!error)
|
||||
nd_jump_link(&ns_path);
|
||||
@@ -67,7 +67,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl
|
||||
if (!task)
|
||||
return res;
|
||||
|
||||
if (ptrace_may_access(task, PTRACE_MODE_READ)) {
|
||||
if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
|
||||
res = ns_get_name(name, sizeof(name), task, ns_ops);
|
||||
if (res >= 0)
|
||||
res = readlink_copy(buffer, buflen, name);
|
||||
|
@@ -468,7 +468,7 @@ struct mem_size_stats {
|
||||
static void smaps_account(struct mem_size_stats *mss, struct page *page,
|
||||
bool compound, bool young, bool dirty)
|
||||
{
|
||||
int i, nr = compound ? HPAGE_PMD_NR : 1;
|
||||
int i, nr = compound ? 1 << compound_order(page) : 1;
|
||||
unsigned long size = nr * PAGE_SIZE;
|
||||
|
||||
if (PageAnon(page))
|
||||
|
Reference in New Issue
Block a user