diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fat/inode.c | 11 | ||||
-rw-r--r-- | fs/ntfs/runlist.c | 55 | ||||
-rw-r--r-- | fs/proc/base.c | 84 |
3 files changed, 118 insertions, 32 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 51b1d15d9d5c..e2effe2dc9b2 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -300,9 +300,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) inode->i_blksize = sbi->cluster_size; inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) & ~((loff_t)sbi->cluster_size - 1)) >> 9; - inode->i_mtime.tv_sec = inode->i_atime.tv_sec = + inode->i_mtime.tv_sec = date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); - inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; if (sbi->options.isvfat) { int secs = de->ctime_cs / 100; int csecs = de->ctime_cs % 100; @@ -310,8 +310,11 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) date_dos2unix(le16_to_cpu(de->ctime), le16_to_cpu(de->cdate)) + secs; inode->i_ctime.tv_nsec = csecs * 10000000; + inode->i_atime.tv_sec = + date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate)); + inode->i_atime.tv_nsec = 0; } else - inode->i_ctime = inode->i_mtime; + inode->i_ctime = inode->i_atime = inode->i_mtime; return 0; } @@ -513,7 +516,9 @@ retry: raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); if (sbi->options.isvfat) { + __le16 atime; fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); + fat_date_unix2dos(inode->i_atime.tv_sec,&atime,&raw_entry->adate); raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + inode->i_ctime.tv_nsec / 10000000; } diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index e2665d011d72..061b5ff6b73c 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -158,17 +158,21 @@ static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst, BUG_ON(!dst); BUG_ON(!src); - if ((dst->lcn < 0) || (src->lcn < 0)) { /* Are we merging holes? */ - if (dst->lcn == LCN_HOLE && src->lcn == LCN_HOLE) - return TRUE; + /* We can merge unmapped regions even if they are misaligned. */ + if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED)) + return TRUE; + /* If the runs are misaligned, we cannot merge them. */ + if ((dst->vcn + dst->length) != src->vcn) return FALSE; - } - if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */ - return FALSE; - if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */ - return FALSE; - - return TRUE; + /* If both runs are non-sparse and contiguous, we can merge them. */ + if ((dst->lcn >= 0) && (src->lcn >= 0) && + ((dst->lcn + dst->length) == src->lcn)) + return TRUE; + /* If we are merging two holes, we can merge them. */ + if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE)) + return TRUE; + /* Cannot merge. */ + return FALSE; } /** @@ -214,14 +218,15 @@ static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) static inline runlist_element *ntfs_rl_append(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL right; /* Right end of @src needs merging. */ - int marker; /* End of the inserted runs. */ + BOOL right = FALSE; /* Right end of @src needs merging. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); /* First, check if the right hand end needs merging. */ - right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); + if ((loc + 1) < dsize) + right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); /* Space required: @dst size + @src size, less one if we merged. */ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); @@ -377,20 +382,21 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { BOOL left = FALSE; /* Left end of @src needs merging. */ - BOOL right; /* Right end of @src needs merging. */ + BOOL right = FALSE; /* Right end of @src needs merging. */ int tail; /* Start of tail of @dst. */ int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); - /* First, merge the left and right ends, if necessary. */ - right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); + /* First, see if the left and right ends need merging. */ + if ((loc + 1) < dsize) + right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); if (loc > 0) left = ntfs_are_rl_mergeable(dst + loc - 1, src); /* * Allocate some space. We will need less if the left, right, or both - * ends were merged. + * ends get merged. */ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right); if (IS_ERR(dst)) @@ -399,21 +405,26 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, * We are guaranteed to succeed from here so can start modifying the * original runlists. */ + + /* First, merge the left and right ends, if necessary. */ if (right) __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); if (left) __ntfs_rl_merge(dst + loc - 1, src); /* - * First run of @dst that needs to be moved out of the way to make - * space for the runs to be copied from @src, i.e. the first run of the - * tail of @dst. + * Offset of the tail of @dst. This needs to be moved out of the way + * to make space for the runs to be copied from @src, i.e. the first + * run of the tail of @dst. + * Nominally, @tail equals @loc + 1, i.e. location, skipping the + * replaced run. However, if @right, then one of @dst's runs is + * already merged into @src. */ tail = loc + right + 1; /* * First run after the @src runs that have been inserted, i.e. where * the tail of @dst needs to be moved to. - * Nominally, marker equals @loc + @ssize, i.e. location + number of - * runs in @src). However, if @left, then the first run in @src has + * Nominally, @marker equals @loc + @ssize, i.e. location + number of + * runs in @src. However, if @left, then the first run in @src has * been merged with one in @dst. */ marker = loc + ssize - left; diff --git a/fs/proc/base.c b/fs/proc/base.c index 23db452ab428..fb34f88a4a74 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -340,6 +340,52 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf return result; } + +/* Same as proc_root_link, but this addionally tries to get fs from other + * threads in the group */ +static int proc_task_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) +{ + struct fs_struct *fs; + int result = -ENOENT; + struct task_struct *leader = proc_task(inode); + + task_lock(leader); + fs = leader->fs; + if (fs) { + atomic_inc(&fs->count); + task_unlock(leader); + } else { + /* Try to get fs from other threads */ + task_unlock(leader); + struct task_struct *task = leader; + read_lock(&tasklist_lock); + if (pid_alive(task)) { + while ((task = next_thread(task)) != leader) { + task_lock(task); + fs = task->fs; + if (fs) { + atomic_inc(&fs->count); + task_unlock(task); + break; + } + task_unlock(task); + } + } + read_unlock(&tasklist_lock); + } + + if (fs) { + read_lock(&fs->lock); + *mnt = mntget(fs->rootmnt); + *dentry = dget(fs->root); + read_unlock(&fs->lock); + result = 0; + put_fs_struct(fs); + } + return result; +} + + #define MAY_PTRACE(task) \ (task == current || \ (task->parent == current && \ @@ -471,14 +517,14 @@ static int proc_oom_score(struct task_struct *task, char *buffer) /* permission checks */ -static int proc_check_root(struct inode *inode) +/* If the process being read is separated by chroot from the reading process, + * don't let the reader access the threads. + */ +static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) { - struct dentry *de, *base, *root; - struct vfsmount *our_vfsmnt, *vfsmnt, *mnt; + struct dentry *de, *base; + struct vfsmount *our_vfsmnt, *mnt; int res = 0; - - if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ - return -ENOENT; read_lock(¤t->fs->lock); our_vfsmnt = mntget(current->fs->rootmnt); base = dget(current->fs->root); @@ -511,6 +557,16 @@ out: goto exit; } +static int proc_check_root(struct inode *inode) +{ + struct dentry *root; + struct vfsmount *vfsmnt; + + if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ + return -ENOENT; + return proc_check_chroot(root, vfsmnt); +} + static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) { if (generic_permission(inode, mask, NULL) != 0) @@ -518,6 +574,20 @@ static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) return proc_check_root(inode); } +static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + struct dentry *root; + struct vfsmount *vfsmnt; + + if (generic_permission(inode, mask, NULL) != 0) + return -EACCES; + + if (proc_task_root_link(inode, &root, &vfsmnt)) + return -ENOENT; + + return proc_check_chroot(root, vfsmnt); +} + extern struct seq_operations proc_pid_maps_op; static int maps_open(struct inode *inode, struct file *file) { @@ -1419,7 +1489,7 @@ static struct inode_operations proc_fd_inode_operations = { static struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, - .permission = proc_permission, + .permission = proc_task_permission, }; #ifdef CONFIG_SECURITY |