Merge branch 'upstream'

This commit is contained in:
Darik Horn 2013-01-14 18:55:59 -06:00
commit 67572ee8c5
9 changed files with 220 additions and 61 deletions

View File

@ -78,11 +78,14 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
SPL_AC_EXPORTED_RWSEM_IS_LOCKED
SPL_AC_KERNEL_INVALIDATE_INODES
SPL_AC_KERNEL_2ARGS_INVALIDATE_INODES
SPL_AC_KERNEL_FALLOCATE
SPL_AC_SHRINK_DCACHE_MEMORY
SPL_AC_SHRINK_ICACHE_MEMORY
SPL_AC_KERN_PATH_PARENT_HEADER
SPL_AC_KERN_PATH_PARENT_SYMBOL
SPL_AC_KERN_PATH_LOCKED
SPL_AC_CONFIG_ZLIB_INFLATE
SPL_AC_CONFIG_ZLIB_DEFLATE
SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE
SPL_AC_SHRINK_CONTROL_STRUCT
SPL_AC_RWSEM_SPINLOCK_IS_RAW
@ -1311,9 +1314,12 @@ dnl #
AC_DEFUN([SPL_AC_3ARGS_ON_EACH_CPU], [
AC_MSG_CHECKING([whether on_each_cpu() wants 3 args])
SPL_LINUX_TRY_COMPILE([
#include <linux/interrupt.h>
#include <linux/smp.h>
void on_each_cpu_func(void *data) { return; }
],[
on_each_cpu(NULL, NULL, 0);
on_each_cpu(on_each_cpu_func, NULL, 0);
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_3ARGS_ON_EACH_CPU, 1,
@ -1922,7 +1928,6 @@ AC_DEFUN([SPL_AC_2ARGS_VFS_FSYNC], [
dnl #
dnl # 3.5 API change,
dnl # inode_operations.truncate_range removed
dnl # (deprecated in favor of FALLOC_FL_PUNCH_HOLE)
dnl #
AC_DEFUN([SPL_AC_INODE_TRUNCATE_RANGE], [
AC_MSG_CHECKING([whether truncate_range() inode operation is available])
@ -1938,7 +1943,77 @@ AC_DEFUN([SPL_AC_INODE_TRUNCATE_RANGE], [
],[
AC_MSG_RESULT(no)
])
]))
])
dnl #
dnl # Linux 2.6.38 - 3.x API
dnl #
AC_DEFUN([SPL_AC_KERNEL_FILE_FALLOCATE], [
AC_MSG_CHECKING([whether fops->fallocate() exists])
SPL_LINUX_TRY_COMPILE([
#include <linux/fs.h>
],[
long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
struct file_operations fops __attribute__ ((unused)) = {
.fallocate = fallocate,
};
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
],[
AC_MSG_RESULT(no)
])
])
dnl #
dnl # Linux 2.6.x - 2.6.37 API
dnl #
AC_DEFUN([SPL_AC_KERNEL_INODE_FALLOCATE], [
AC_MSG_CHECKING([whether iops->fallocate() exists])
SPL_LINUX_TRY_COMPILE([
#include <linux/fs.h>
],[
long (*fallocate) (struct inode *, int, loff_t, loff_t) = NULL;
struct inode_operations fops __attribute__ ((unused)) = {
.fallocate = fallocate,
};
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_INODE_FALLOCATE, 1, [fops->fallocate() exists])
],[
AC_MSG_RESULT(no)
])
])
dnl #
dnl # PaX Linux 2.6.38 - 3.x API
dnl #
AC_DEFUN([SPL_AC_PAX_KERNEL_FILE_FALLOCATE], [
AC_MSG_CHECKING([whether fops->fallocate() exists])
SPL_LINUX_TRY_COMPILE([
#include <linux/fs.h>
],[
long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
struct file_operations_no_const fops __attribute__ ((unused)) = {
.fallocate = fallocate,
};
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
],[
AC_MSG_RESULT(no)
])
])
dnl #
dnl # The fallocate callback was moved from the inode_operations
dnl # structure to the file_operations structure.
dnl #
AC_DEFUN([SPL_AC_KERNEL_FALLOCATE], [
SPL_AC_KERNEL_FILE_FALLOCATE
SPL_AC_KERNEL_INODE_FALLOCATE
SPL_AC_PAX_KERNEL_FILE_FALLOCATE
])
dnl #
dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
@ -2128,6 +2203,48 @@ AC_DEFUN([SPL_AC_KERN_PATH_LOCKED], [
[])
])
dnl #
dnl # zlib inflate compat,
dnl # Verify the kernel has CONFIG_ZLIB_INFLATE support enabled.
dnl #
AC_DEFUN([SPL_AC_CONFIG_ZLIB_INFLATE], [
AC_MSG_CHECKING([whether CONFIG_ZLIB_INFLATE is defined])
SPL_LINUX_TRY_COMPILE([
#if !defined(CONFIG_ZLIB_INFLATE) && \
!defined(CONFIG_ZLIB_INFLATE_MODULE)
#error CONFIG_ZLIB_INFLATE not defined
#endif
],[ ],[
AC_MSG_RESULT([yes])
],[
AC_MSG_RESULT([no])
AC_MSG_ERROR([
*** This kernel does not include the required zlib inflate support.
*** Rebuild the kernel with CONFIG_ZLIB_INFLATE=y|m set.])
])
])
dnl #
dnl # zlib deflate compat,
dnl # Verify the kernel has CONFIG_ZLIB_DEFLATE support enabled.
dnl #
AC_DEFUN([SPL_AC_CONFIG_ZLIB_DEFLATE], [
AC_MSG_CHECKING([whether CONFIG_ZLIB_DEFLATE is defined])
SPL_LINUX_TRY_COMPILE([
#if !defined(CONFIG_ZLIB_DEFLATE) && \
!defined(CONFIG_ZLIB_DEFLATE_MODULE)
#error CONFIG_ZLIB_DEFLATE not defined
#endif
],[ ],[
AC_MSG_RESULT([yes])
],[
AC_MSG_RESULT([no])
AC_MSG_ERROR([
*** This kernel does not include the required zlib deflate support.
*** Rebuild the kernel with CONFIG_ZLIB_DEFLATE=y|m set.])
])
])
dnl #
dnl # 2.6.39 API compat,
dnl # The function zlib_deflate_workspacesize() now take 2 arguments.

View File

@ -50,6 +50,26 @@ spl_filp_open(const char *name, int flags, int mode, int *err)
#define spl_filp_poff(f) (&(f)->f_pos)
#define spl_filp_write(fp, b, s, p) (fp)->f_op->write((fp), (b), (s), p)
static inline int
spl_filp_fallocate(struct file *fp, int mode, loff_t offset, loff_t len)
{
int error = -EOPNOTSUPP;
#ifdef HAVE_FILE_FALLOCATE
if (fp->f_op->fallocate)
error = fp->f_op->fallocate(fp, mode, offset, len);
#else
# ifdef HAVE_INODE_FALLOCATE
if (fp->f_dentry && fp->f_dentry->d_inode &&
fp->f_dentry->d_inode->i_op->fallocate)
error = fp->f_dentry->d_inode->i_op->fallocate(
fp->f_dentry->d_inode, mode, offset, len);
# endif /* HAVE_INODE_FALLOCATE */
#endif /*HAVE_FILE_FALLOCATE */
return (error);
}
#ifdef HAVE_VFS_FSYNC
# ifdef HAVE_2ARGS_VFS_FSYNC
# define spl_filp_fsync(fp, sync) vfs_fsync(fp, sync)

View File

@ -51,6 +51,7 @@ typedef enum { CV_DEFAULT=0, CV_DRIVER } kcv_type_t;
extern void __cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg);
extern void __cv_destroy(kcondvar_t *cvp);
extern void __cv_wait(kcondvar_t *cvp, kmutex_t *mp);
extern void __cv_wait_io(kcondvar_t *cvp, kmutex_t *mp);
extern void __cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp);
extern clock_t __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time);
extern clock_t __cv_timedwait_interruptible(kcondvar_t *cvp, kmutex_t *mp,
@ -61,6 +62,7 @@ extern void __cv_broadcast(kcondvar_t *cvp);
#define cv_init(cvp, name, type, arg) __cv_init(cvp, name, type, arg)
#define cv_destroy(cvp) __cv_destroy(cvp)
#define cv_wait(cvp, mp) __cv_wait(cvp, mp)
#define cv_wait_io(cvp, mp) __cv_wait_io(cvp, mp)
#define cv_wait_interruptible(cvp, mp) __cv_wait_interruptible(cvp,mp)
#define cv_timedwait(cvp, mp, t) __cv_timedwait(cvp, mp, t)
#define cv_timedwait_interruptible(cvp, mp, t) \

View File

@ -97,7 +97,7 @@ __cv_destroy(kcondvar_t *cvp)
EXPORT_SYMBOL(__cv_destroy);
static void
cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state)
cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state, int io)
{
DEFINE_WAIT(wait);
SENTRY;
@ -121,6 +121,9 @@ cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state)
* ensures we're linked in to the waiters list and avoids the
* race where 'cvp->cv_waiters > 0' but the list is empty. */
mutex_exit(mp);
if (io)
io_schedule();
else
schedule();
mutex_enter(mp);
@ -139,17 +142,24 @@ cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state)
void
__cv_wait(kcondvar_t *cvp, kmutex_t *mp)
{
cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE);
cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE, 0);
}
EXPORT_SYMBOL(__cv_wait);
void
__cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp)
{
cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE);
cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE, 0);
}
EXPORT_SYMBOL(__cv_wait_interruptible);
void
__cv_wait_io(kcondvar_t *cvp, kmutex_t *mp)
{
cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE, 1);
}
EXPORT_SYMBOL(__cv_wait_io);
/* 'expire_time' argument is an absolute wall clock time in jiffies.
* Return value is time left (expire_time - now) or -1 if timeout occurred.
*/

View File

@ -536,7 +536,7 @@ hostid_exec(void)
* '/usr/bin/hostid' and redirect the result to /proc/sys/spl/hostid
* for us to use. It's a horrific solution but it will do for now.
*/
rc = call_usermodehelper(argv[0], argv, envp, 1);
rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
if (rc)
printk("SPL: Failed user helper '%s %s %s', rc = %d\n",
argv[0], argv[1], argv[2], rc);
@ -607,7 +607,7 @@ set_kallsyms_lookup_name(void)
NULL };
int rc;
rc = call_usermodehelper(argv[0], argv, envp, 1);
rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
/*
* Due to I/O buffering the helper may return successfully before

View File

@ -827,8 +827,7 @@ struct list_head spl_kmem_cache_list; /* List of caches */
struct rw_semaphore spl_kmem_cache_sem; /* Cache list lock */
taskq_t *spl_kmem_cache_taskq; /* Task queue for ageing / reclaim */
static int spl_cache_flush(spl_kmem_cache_t *skc,
spl_kmem_magazine_t *skm, int flush);
static void spl_cache_shrink(spl_kmem_cache_t *skc, void *obj);
SPL_SHRINKER_CALLBACK_FWD_DECLARE(spl_kmem_cache_generic_shrinker);
SPL_SHRINKER_DECLARE(spl_kmem_cache_shrinker,
@ -1244,6 +1243,38 @@ spl_emergency_free(spl_kmem_cache_t *skc, void *obj)
SRETURN(0);
}
/*
* Release objects from the per-cpu magazine back to their slab. The flush
* argument contains the max number of entries to remove from the magazine.
*/
static void
__spl_cache_flush(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flush)
{
int i, count = MIN(flush, skm->skm_avail);
SENTRY;
ASSERT(skc->skc_magic == SKC_MAGIC);
ASSERT(skm->skm_magic == SKM_MAGIC);
ASSERT(spin_is_locked(&skc->skc_lock));
for (i = 0; i < count; i++)
spl_cache_shrink(skc, skm->skm_objs[i]);
skm->skm_avail -= count;
memmove(skm->skm_objs, &(skm->skm_objs[count]),
sizeof(void *) * skm->skm_avail);
SEXIT;
}
static void
spl_cache_flush(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flush)
{
spin_lock(&skc->skc_lock);
__spl_cache_flush(skc, skm, flush);
spin_unlock(&skc->skc_lock);
}
static void
spl_magazine_age(void *data)
{
@ -1252,10 +1283,23 @@ spl_magazine_age(void *data)
ASSERT(skm->skm_magic == SKM_MAGIC);
ASSERT(skm->skm_cpu == smp_processor_id());
ASSERT(irqs_disabled());
if (skm->skm_avail > 0)
if (time_after(jiffies, skm->skm_age + skc->skc_delay * HZ))
(void) spl_cache_flush(skc, skm, skm->skm_refill);
/* There are no available objects or they are too young to age out */
if ((skm->skm_avail == 0) ||
time_before(jiffies, skm->skm_age + skc->skc_delay * HZ))
return;
/*
* Because we're executing in interrupt context we may have
* interrupted the holder of this lock. To avoid a potential
* deadlock return if the lock is contended.
*/
if (!spin_trylock(&skc->skc_lock))
return;
__spl_cache_flush(skc, skm, skm->skm_refill);
spin_unlock(&skc->skc_lock);
}
/*
@ -1451,7 +1495,7 @@ spl_magazine_destroy(spl_kmem_cache_t *skc)
for_each_online_cpu(i) {
skm = skc->skc_mag[i];
(void)spl_cache_flush(skc, skm, skm->skm_avail);
spl_cache_flush(skc, skm, skm->skm_avail);
spl_magazine_free(skm);
}
@ -1931,42 +1975,6 @@ spl_cache_shrink(spl_kmem_cache_t *skc, void *obj)
SEXIT;
}
/*
* Release a batch of objects from a per-cpu magazine back to their
* respective slabs. This occurs when we exceed the magazine size,
* are under memory pressure, when the cache is idle, or during
* cache cleanup. The flush argument contains the number of entries
* to remove from the magazine.
*/
static int
spl_cache_flush(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flush)
{
int i, count = MIN(flush, skm->skm_avail);
SENTRY;
ASSERT(skc->skc_magic == SKC_MAGIC);
ASSERT(skm->skm_magic == SKM_MAGIC);
/*
* XXX: Currently we simply return objects from the magazine to
* the slabs in fifo order. The ideal thing to do from a memory
* fragmentation standpoint is to cheaply determine the set of
* objects in the magazine which will result in the largest
* number of free slabs if released from the magazine.
*/
spin_lock(&skc->skc_lock);
for (i = 0; i < count; i++)
spl_cache_shrink(skc, skm->skm_objs[i]);
skm->skm_avail -= count;
memmove(skm->skm_objs, &(skm->skm_objs[count]),
sizeof(void *) * skm->skm_avail);
spin_unlock(&skc->skc_lock);
SRETURN(count);
}
/*
* Allocate an object from the per-cpu magazine, or if the magazine
* is empty directly allocate from a slab and repopulate the magazine.
@ -2053,7 +2061,7 @@ spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj)
/* Per-CPU cache full, flush it to make space */
if (unlikely(skm->skm_avail >= skm->skm_size))
(void)spl_cache_flush(skc, skm, skm->skm_refill);
spl_cache_flush(skc, skm, skm->skm_refill);
/* Available space in cache, use it */
skm->skm_objs[skm->skm_avail++] = obj;

View File

@ -654,13 +654,15 @@ int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
#ifdef FALLOC_FL_PUNCH_HOLE
if (vp->v_file->f_op->fallocate) {
error = -vp->v_file->f_op->fallocate(vp->v_file,
/*
* When supported by the underlying file system preferentially
* use the fallocate() callback to preallocate the space.
*/
error = -spl_filp_fallocate(vp->v_file,
FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
bfp->l_start, bfp->l_len);
if (!error)
if (error == 0)
SRETURN(0);
}
#endif
#ifdef HAVE_INODE_TRUNCATE_RANGE

View File

@ -166,7 +166,7 @@ splat_linux_drop_slab(struct file *file)
NULL };
int rc;
rc = call_usermodehelper(argv[0], argv, envp, 1);
rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
if (rc)
splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
"Failed user helper '%s %s %s', rc = %d\n",

View File

@ -75,7 +75,7 @@ splat_vnode_user_cmd(struct file *file, void *arg,
NULL };
int rc;
rc = call_usermodehelper(sh_path, argv, envp, 1);
rc = call_usermodehelper(sh_path, argv, envp, UMH_WAIT_PROC);
if (rc) {
splat_vprint(file, name,
"Failed command: %s %s %s (%d)\n",