Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19e7b5f9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull misc vfs updates from Al Viro:
 "All kinds of misc stuff, without any unifying topic, from various
  people.

  Neil's d_anon patch, several bugfixes, introduction of kvmalloc
  analogue of kmemdup_user(), extending bitfield.h to deal with
  fixed-endians, assorted cleanups all over the place..."

* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (28 commits)
  alpha: osf_sys.c: use timespec64 where appropriate
  alpha: osf_sys.c: fix put_tv32 regression
  jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path
  dcache: delete unused d_hash_mask
  dcache: subtract d_hash_shift from 32 in advance
  fs/buffer.c: fold init_buffer() into init_page_buffers()
  fs: fold __inode_permission() into inode_permission()
  fs: add RWF_APPEND
  sctp: use vmemdup_user() rather than badly open-coding memdup_user()
  snd_ctl_elem_init_enum_names(): switch to vmemdup_user()
  replace_user_tlv(): switch to vmemdup_user()
  new primitive: vmemdup_user()
  memdup_user(): switch to GFP_USER
  eventfd: fold eventfd_ctx_get() into eventfd_ctx_fileget()
  eventfd: fold eventfd_ctx_read() into eventfd_read()
  eventfd: convert to use anon_inode_getfd()
  nfs4file: get rid of pointless include of btrfs.h
  uvc_v4l2: clean copyin/copyout up
  vme_user: don't use __copy_..._user()
  usx2y: don't bother with memdup_user() for 16-byte structure
  ...
parents 26064ea4 ce4c2535
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -56,13 +56,25 @@ a/ A dentry flag DCACHE_DISCONNECTED which is set on
   any dentry that might not be part of the proper prefix.
   This is set when anonymous dentries are created, and cleared when a
   dentry is noticed to be a child of a dentry which is in the proper
   prefix. 

b/ A per-superblock list "s_anon" of dentries which are the roots of
   subtrees that are not in the proper prefix.  These dentries, as
   well as the proper prefix, need to be released at unmount time.  As
   these dentries will not be hashed, they are linked together on the
   d_hash list_head.
   prefix.  If the refcount on a dentry with this flag set
   becomes zero, the dentry is immediately discarded, rather than being
   kept in the dcache.  If a dentry that is not already in the dcache
   is repeatedly accessed by filehandle (as NFSD might do), an new dentry
   will be a allocated for each access, and discarded at the end of
   the access.

   Note that such a dentry can acquire children, name, ancestors, etc.
   without losing DCACHE_DISCONNECTED - that flag is only cleared when
   subtree is successfully reconnected to root.  Until then dentries
   in such subtree are retained only as long as there are references;
   refcount reaching zero means immediate eviction, same as for unhashed
   dentries.  That guarantees that we won't need to hunt them down upon
   umount.

b/ A primitive for creation of secondary roots - d_obtain_root(inode).
   Those do _not_ bear DCACHE_DISCONNECTED.  They are placed on the
   per-superblock list (->s_roots), so they can be located at umount
   time for eviction purposes.

c/ Helper routines to allocate anonymous dentries, and to help attach
   loose directory dentries at lookup time. They are:
@@ -78,7 +90,6 @@ c/ Helper routines to allocate anonymous dentries, and to help attach
      It returns NULL when the passed-in dentry is used, following the calling
      convention of ->lookup.
 
 
Filesystem Issues
-----------------

+36 −36
Original line number Diff line number Diff line
@@ -950,22 +950,31 @@ struct itimerval32
};

static inline long
get_tv32(struct timeval *o, struct timeval32 __user *i)
get_tv32(struct timespec64 *o, struct timeval32 __user *i)
{
	struct timeval32 tv;
	if (copy_from_user(&tv, i, sizeof(struct timeval32)))
		return -EFAULT;
	o->tv_sec = tv.tv_sec;
	o->tv_usec = tv.tv_usec;
	o->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
	return 0;
}

static inline long
put_tv32(struct timeval32 __user *o, struct timeval *i)
put_tv32(struct timeval32 __user *o, struct timespec64 *i)
{
	return copy_to_user(o, &(struct timeval32){
				.tv_sec = o->tv_sec,
				.tv_usec = o->tv_usec},
				.tv_sec = i->tv_sec,
				.tv_usec = i->tv_nsec / NSEC_PER_USEC},
			    sizeof(struct timeval32));
}

static inline long
put_tv_to_tv32(struct timeval32 __user *o, struct timeval *i)
{
	return copy_to_user(o, &(struct timeval32){
				.tv_sec = i->tv_sec,
				.tv_usec = i->tv_usec},
			    sizeof(struct timeval32));
}

@@ -1004,9 +1013,10 @@ SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv,
		struct timezone __user *, tz)
{
	if (tv) {
		struct timeval ktv;
		do_gettimeofday(&ktv);
		if (put_tv32(tv, &ktv))
		struct timespec64 kts;

		ktime_get_real_ts64(&kts);
		if (put_tv32(tv, &kts))
			return -EFAULT;
	}
	if (tz) {
@@ -1019,22 +1029,19 @@ SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv,
SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
		struct timezone __user *, tz)
{
	struct timespec64 kts64;
	struct timespec kts;
	struct timespec64 kts;
	struct timezone ktz;

 	if (tv) {
		if (get_tv32((struct timeval *)&kts, tv))
		if (get_tv32(&kts, tv))
			return -EFAULT;
		kts.tv_nsec *= 1000;
		kts64 = timespec_to_timespec64(kts);
	}
	if (tz) {
		if (copy_from_user(&ktz, tz, sizeof(*tz)))
			return -EFAULT;
	}

	return do_sys_settimeofday64(tv ? &kts64 : NULL, tz ? &ktz : NULL);
	return do_sys_settimeofday64(tv ? &kts : NULL, tz ? &ktz : NULL);
}

asmlinkage long sys_ni_posix_timers(void);
@@ -1083,22 +1090,16 @@ SYSCALL_DEFINE3(osf_setitimer, int, which, struct itimerval32 __user *, in,
SYSCALL_DEFINE2(osf_utimes, const char __user *, filename,
		struct timeval32 __user *, tvs)
{
	struct timespec tv[2];
	struct timespec64 tv[2];

	if (tvs) {
		struct timeval ktvs[2];
		if (get_tv32(&ktvs[0], &tvs[0]) ||
		    get_tv32(&ktvs[1], &tvs[1]))
		if (get_tv32(&tv[0], &tvs[0]) ||
		    get_tv32(&tv[1], &tvs[1]))
			return -EFAULT;

		if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
		    ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
		if (tv[0].tv_nsec < 0 || tv[0].tv_nsec >= 1000000000 ||
		    tv[1].tv_nsec < 0 || tv[1].tv_nsec >= 1000000000)
			return -EINVAL;

		tv[0].tv_sec = ktvs[0].tv_sec;
		tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
		tv[1].tv_sec = ktvs[1].tv_sec;
		tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
	}

	return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
@@ -1107,19 +1108,18 @@ SYSCALL_DEFINE2(osf_utimes, const char __user *, filename,
SYSCALL_DEFINE5(osf_select, int, n, fd_set __user *, inp, fd_set __user *, outp,
		fd_set __user *, exp, struct timeval32 __user *, tvp)
{
	struct timespec end_time, *to = NULL;
	struct timespec64 end_time, *to = NULL;
	if (tvp) {
		struct timeval tv;
		struct timespec64 tv;
		to = &end_time;

		if (get_tv32(&tv, tvp))
		    	return -EFAULT;

		if (tv.tv_sec < 0 || tv.tv_usec < 0)
		if (tv.tv_sec < 0 || tv.tv_nsec < 0)
			return -EINVAL;

		if (poll_select_set_timeout(to, tv.tv_sec,
					    tv.tv_usec * NSEC_PER_USEC))
		if (poll_select_set_timeout(to, tv.tv_sec, tv.tv_nsec))
			return -EINVAL;		

	}
@@ -1192,9 +1192,9 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
		return -EFAULT;
	if (!ur)
		return err;
	if (put_tv32(&ur->ru_utime, &r.ru_utime))
	if (put_tv_to_tv32(&ur->ru_utime, &r.ru_utime))
		return -EFAULT;
	if (put_tv32(&ur->ru_stime, &r.ru_stime))
	if (put_tv_to_tv32(&ur->ru_stime, &r.ru_stime))
		return -EFAULT;
	if (copy_to_user(&ur->ru_maxrss, &r.ru_maxrss,
	      sizeof(struct rusage32) - offsetof(struct rusage32, ru_maxrss)))
@@ -1210,18 +1210,18 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
SYSCALL_DEFINE2(osf_usleep_thread, struct timeval32 __user *, sleep,
		struct timeval32 __user *, remain)
{
	struct timeval tmp;
	struct timespec64 tmp;
	unsigned long ticks;

	if (get_tv32(&tmp, sleep))
		goto fault;

	ticks = timeval_to_jiffies(&tmp);
	ticks = timespec64_to_jiffies(&tmp);

	ticks = schedule_timeout_interruptible(ticks);

	if (remain) {
		jiffies_to_timeval(ticks, &tmp);
		jiffies_to_timespec64(ticks, &tmp);
		if (put_tv32(remain, &tmp))
			goto fault;
	}
@@ -1280,7 +1280,7 @@ SYSCALL_DEFINE1(old_adjtimex, struct timex32 __user *, txc_p)
	if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
	    (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - 
			  offsetof(struct timex32, tick))) ||
	    (put_tv32(&txc_p->time, &txc.time)))
	    (put_tv_to_tv32(&txc_p->time, &txc.time)))
	  return -EFAULT;

	return ret;
+6 −17
Original line number Diff line number Diff line
@@ -982,25 +982,14 @@ static int r128_cce_dispatch_write_pixels(struct drm_device *dev,

	xbuf_size = count * sizeof(*x);
	ybuf_size = count * sizeof(*y);
	x = kmalloc(xbuf_size, GFP_KERNEL);
	if (x == NULL)
		return -ENOMEM;
	y = kmalloc(ybuf_size, GFP_KERNEL);
	if (y == NULL) {
		kfree(x);
		return -ENOMEM;
	}
	if (copy_from_user(x, depth->x, xbuf_size)) {
		kfree(x);
		kfree(y);
		return -EFAULT;
	}
	if (copy_from_user(y, depth->y, xbuf_size)) {
	x = memdup_user(depth->x, xbuf_size);
	if (IS_ERR(x))
		return PTR_ERR(x);
	y = memdup_user(depth->y, ybuf_size);
	if (IS_ERR(y)) {
		kfree(x);
		kfree(y);
		return -EFAULT;
		return PTR_ERR(y);
	}

	buffer_size = depth->n * sizeof(u32);
	buffer = memdup_user(depth->buffer, buffer_size);
	if (IS_ERR(buffer)) {
+22 −33
Original line number Diff line number Diff line
@@ -1284,36 +1284,30 @@ struct uvc_xu_control_mapping32 {
static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
			const struct uvc_xu_control_mapping32 __user *up)
{
	compat_caddr_t p;
	struct uvc_xu_control_mapping32 *p = (void *)kp;
	compat_caddr_t info;
	u32 count;

	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
	    __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) ||
	    __get_user(kp->menu_count, &up->menu_count))
	if (copy_from_user(p, up, sizeof(*p)))
		return -EFAULT;

	memset(kp->reserved, 0, sizeof(kp->reserved));

	if (kp->menu_count == 0) {
		kp->menu_info = NULL;
		return 0;
	}

	if (__get_user(p, &up->menu_info))
		return -EFAULT;
	kp->menu_info = compat_ptr(p);
	count = p->menu_count;
	info = p->menu_info;

	memset(kp->reserved, 0, sizeof(kp->reserved));
	kp->menu_info = count ? compat_ptr(info) : NULL;
	kp->menu_count = count;
	return 0;
}

static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
			struct uvc_xu_control_mapping32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
	    __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
	    __put_user(kp->menu_count, &up->menu_count))
	if (copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
	    put_user(kp->menu_count, &up->menu_count))
		return -EFAULT;

	if (__clear_user(up->reserved, sizeof(up->reserved)))
	if (clear_user(up->reserved, sizeof(up->reserved)))
		return -EFAULT;

	return 0;
@@ -1330,31 +1324,26 @@ struct uvc_xu_control_query32 {
static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
			const struct uvc_xu_control_query32 __user *up)
{
	compat_caddr_t p;
	struct uvc_xu_control_query32 v;

	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
	    __copy_from_user(kp, up, offsetof(typeof(*up), data)))
	if (copy_from_user(&v, up, sizeof(v)))
		return -EFAULT;

	if (kp->size == 0) {
		kp->data = NULL;
		return 0;
	}

	if (__get_user(p, &up->data))
		return -EFAULT;
	kp->data = compat_ptr(p);

	*kp = (struct uvc_xu_control_query){
		.unit = v.unit,
		.selector = v.selector,
		.query = v.query,
		.size = v.size,
		.data = v.size ? compat_ptr(v.data) : NULL
	};
	return 0;
}

static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
			struct uvc_xu_control_query32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
	    __copy_to_user(up, kp, offsetof(typeof(*up), data)))
	if (copy_to_user(up, kp, offsetof(typeof(*up), data)))
		return -EFAULT;

	return 0;
}

+1 −9
Original line number Diff line number Diff line
@@ -1296,15 +1296,7 @@ static inline void d_lustre_invalidate(struct dentry *dentry, int nested)
	spin_lock_nested(&dentry->d_lock,
			 nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL);
	ll_d2d(dentry)->lld_invalid = 1;
	/*
	 * We should be careful about dentries created by d_obtain_alias().
	 * These dentries are not put in the dentry tree, instead they are
	 * linked to sb->s_anon through dentry->d_hash.
	 * shrink_dcache_for_umount() shrinks the tree and sb->s_anon list.
	 * If we unhashed such a dentry, unmount would not be able to find
	 * it and busy inodes would be reported.
	 */
	if (d_count(dentry) == 0 && !(dentry->d_flags & DCACHE_DISCONNECTED))
	if (d_count(dentry) == 0)
		__d_drop(dentry);
	spin_unlock(&dentry->d_lock);
}
Loading