linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GIT PULL] notification tree changes for 3.8
@ 2012-12-20 22:38 Eric Paris
  2012-12-21  1:50 ` Linus Torvalds
  0 siblings, 1 reply; 4+ messages in thread
From: Eric Paris @ 2012-12-20 22:38 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3048 bytes --]

I believe you would get a build failure after this pull due to the
addition of procfs information for *notify fds.  The attached patch from
sfr should be applied during the merge to change the spin_lock in that
patch to the mutex in this patch.

This pull mostly is about locking changes in the fsnotify system.  By
switching the group lock from a spin_lock() to a mutex() we can now hold
the lock across things like iput().  This fixes a problem involving
unmounting a fs and having inodes be busy, first pointed out by FAT, but
reproducible with tmpfs.

This also restores signal driven I/O for inotify, which has been broken
since about 2.6.32.

$ git request-pull v3.6 git://git.infradead.org/users/eparis/notify.git
The following changes since commit a0d271cbfed1dd50278c6b06bead3d00ba0a88f9:

  Linux 3.6 (2012-09-30 16:47:46 -0700)

are available in the git repository at:

  git://git.infradead.org/users/eparis/notify.git for-next

for you to fetch changes up to 1ca39ab9d21ac93f94b9e3eb364ea9a5cf2aba06:

  inotify: automatically restart syscalls (2012-12-11 13:44:37 -0500)

----------------------------------------------------------------
Eric Paris (2):
      fsnotify: make fasync generic for both inotify and fanotify
      inotify: automatically restart syscalls

Lino Sanfilippo (12):
      inotify, fanotify: replace fsnotify_put_group() with fsnotify_destroy_group()
      fsnotify: introduce fsnotify_get_group()
      fsnotify: use reference counting for groups
      fsnotify: take groups mark_lock before mark lock
      fanotify: add an extra flag to mark_remove_from_mask that indicates wheather a mark should be destroyed
      fsnotify: use a mutex instead of a spinlock to protect a groups mark list
      fsnotify: pass group to fsnotify_destroy_mark()
      fsnotify: introduce locked versions of fsnotify_add_mark() and fsnotify_remove_mark()
      fsnotify: dont put marks on temporary list when clearing marks by group
      fsnotify: change locking order
      fanotify: dont merge permission events
      inotify: dont skip removal of watch descriptor if creation of ignored event failed

 fs/notify/dnotify/dnotify.c          |  4 ++--
 fs/notify/fanotify/fanotify.c        |  6 ++++++
 fs/notify/fanotify/fanotify_user.c   | 37 +++++++++++++++++++++++++------------
 fs/notify/group.c                    | 47 +++++++++++++++++++++++++++--------------------
 fs/notify/inode_mark.c               | 14 +++++++++++---
 fs/notify/inotify/inotify_fsnotify.c |  4 +++-
 fs/notify/inotify/inotify_user.c     | 34 ++++++++++++++--------------------
 fs/notify/mark.c                     | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------------------
 fs/notify/notification.c             |  1 +
 fs/notify/vfsmount_mark.c            | 14 +++++++++++---
 include/linux/fsnotify_backend.h     | 31 +++++++++++++++++++++----------
 kernel/audit_tree.c                  | 10 +++++-----
 kernel/audit_watch.c                 |  4 ++--
 13 files changed, 178 insertions(+), 119 deletions(-)

[-- Attachment #2: tmp.patch --]
[-- Type: text/x-patch, Size: 819 bytes --]

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Wed, 19 Dec 2012 11:53:20 +1100
Subject: [PATCH] fsnotify: cope with change from spinlock to mutex

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 fs/notify/fdinfo.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index 514c4b8..238a593 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -27,13 +27,13 @@ static int show_fdinfo(struct seq_file *m, struct file *f,
 	struct fsnotify_mark *mark;
 	int ret = 0;
 
-	spin_lock(&group->mark_lock);
+	mutex_lock(&group->mark_mutex);
 	list_for_each_entry(mark, &group->marks_list, g_list) {
 		ret = show(m, mark);
 		if (ret)
 			break;
 	}
-	spin_unlock(&group->mark_lock);
+	mutex_unlock(&group->mark_mutex);
 	return ret;
 }
 

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [GIT PULL] notification tree changes for 3.8
  2012-12-20 22:38 [GIT PULL] notification tree changes for 3.8 Eric Paris
@ 2012-12-21  1:50 ` Linus Torvalds
  2012-12-21  2:49   ` Eric Paris
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Torvalds @ 2012-12-21  1:50 UTC (permalink / raw)
  To: Eric Paris, Lino Sanfilippo; +Cc: Linux Kernel Mailing List

On Thu, Dec 20, 2012 at 2:38 PM, Eric Paris <eparis@redhat.com> wrote:
> I believe you would get a build failure after this pull due to the
> addition of procfs information for *notify fds.  The attached patch from
> sfr should be applied during the merge to change the spin_lock in that
> patch to the mutex in this patch.

I'm not going to bother pulling this.

It's coming in late in the merge window, it has been rebased days ago,
and it changes fundamental infrastructure.

This has been a huge merge window, and this is just too late and too
surprising. The commits are marked as being written 18 months ago, but
then the commit date is after the merge window started, and sent the
day before it closes.

WTF? If they've waited 18 months, there cannot be this kind of
last-minute hurry now. Why did you wait until the last minute?

                Linus

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [GIT PULL] notification tree changes for 3.8
  2012-12-21  1:50 ` Linus Torvalds
@ 2012-12-21  2:49   ` Eric Paris
  2012-12-21  4:00     ` Linus Torvalds
  0 siblings, 1 reply; 4+ messages in thread
From: Eric Paris @ 2012-12-21  2:49 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Lino Sanfilippo, Linux Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 2347 bytes --]

On Thu, 2012-12-20 at 17:50 -0800, Linus Torvalds wrote:
> On Thu, Dec 20, 2012 at 2:38 PM, Eric Paris <eparis@redhat.com> wrote:
> > I believe you would get a build failure after this pull due to the
> > addition of procfs information for *notify fds.  The attached patch from
> > sfr should be applied during the merge to change the spin_lock in that
> > patch to the mutex in this patch.
> 
> I'm not going to bother pulling this.
> 
> It's coming in late in the merge window, it has been rebased days ago,
> and it changes fundamental infrastructure.
> 
> This has been a huge merge window, and this is just too late and too
> surprising. The commits are marked as being written 18 months ago, but
> then the commit date is after the merge window started, and sent the
> day before it closes.
> 
> WTF? If they've waited 18 months, there cannot be this kind of
> last-minute hurry now. Why did you wait until the last minute?

The changes have been in next for about 18 months.  I've just been a
missing maintainer.  I'm back with some time to fix that fact, but I
understand if you want to reject it on that account.  I'm available now
if something goes wrong.  Most of this work was originally done just as
cleanup, but recently people started complaining about the FAT race/NULL
ptr deref.

https://bugzilla.redhat.com/show_bug.cgi?id=768534

Which got me to finally get off my lazy ass.  When looking to send the
pull request on the first day of the window I realized just how far
behind my tree was and that there was a merge conflict for which sfr had
been carrying a patch forever.  With 3.7 less than a day old I figured
3.6 was a good place to go in order to solve the conflict.  Since I
rebased, it obviously needed more testing and some time in -next.  Which
was why I said to you, back on the 11th, that I was planning to send my
pull request today.

http://marc.info/?l=linux-next&m=135526314222685&w=2

It is a locking change, but if anything goes wrong, at least I've got
time without other work commitments over the next 2 weeks to fix them.
If you are wondering about testing, I've written the attached
notification stressor.  On a dual core box it will cause a kernel panic
is about 1 second on your kernel.  With the patch set it doesn't pop...

Your call, but it does fix a real bug that people are reporting today.

-Eric

[-- Attachment #2: syscall_thrash.c --]
[-- Type: text/x-csrc, Size: 15436 bytes --]

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

/* huerristic on how hard to load a box */
static unsigned int num_cores;
/* number of threads which just read from inotify_fd and ignore the results */
static unsigned int num_data_dumpers;
/* each thread will add a watch to a given file as fast as it can */
static unsigned int num_adder_threads;
/* each thread will remove all watches between low and high as fast as they can */
static unsigned int num_remover_threads;
/* a multiplier for adders and removers so you have X adders per file */
static unsigned int watcher_multiplier;
/* this removes watches from low_wd to low_wd + 3 just for extra removal races */
static unsigned int num_low_remover_threads;
/* create and destroy the files watches are being added to and removed from */
static unsigned int num_file_creaters;
/* how many inotify_fd's we have total (so another multiplier for adders and removers) */
static unsigned int num_inotify_instances;

static char *working_dir = "/tmp/inotify_syscall_thrash";
/* if mounting a real filesystem, where is the source?  (doesn't matter for tmpfs) */
static char *mnt_src;
/* what is the fstype to mount and unmonut? */
static char *fstype = "tmpfs";

static pthread_attr_t attr;

static pthread_mutex_t wait_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t wait_var = PTHREAD_COND_INITIALIZER;
static int wait;
#define WAIT_CHILD do {\
		pthread_mutex_lock(&wait_mutex); \
		if (wait == 0) \
			pthread_cond_wait(&wait_var, &wait_mutex); \
		wait = 0; \
		pthread_mutex_unlock(&wait_mutex); \
	} while (0);
#define WAKE_PARENT do {\
		pthread_mutex_lock(&wait_mutex); \
		wait = 1; \
		pthread_cond_signal(&wait_var); \
		pthread_mutex_unlock(&wait_mutex); \
	} while (0);

struct adder_struct {
	int inotify_fd;
	int file_num;
};

struct operator_struct {
	int inotify_fd;
};

struct thread_data {
	int inotify_fd;
	pthread_t *adders;
	pthread_t *removers;
	pthread_t *lownum_removers;
	pthread_t *data_dumpers;
};

pthread_t *file_creaters;
pthread_t low_wd_reseter;
pthread_t mounter;

static int stopped = 0;

static int high_wd = 0;
static int low_wd = INT_MAX;

static int handle_error(const char *arg)
{
	perror(arg);
	exit(EXIT_FAILURE);
}

static void sigfunc(int sig_num)
{
	if (sig_num == SIGINT)
		stopped = 1;
	else
		printf("Got an unknown signal!\n");
}

/* constantly create and delete all of the files that are bieng watched */
static void *__create_files(__attribute__ ((unused)) void *ptr)
{
	char filename[50];
	unsigned int i;

	fprintf(stdout, "Starting creater thread\n");

	WAKE_PARENT;

	while (!stopped) {
		for (i = 0; i < num_adder_threads; i++) {
			int fd;

			snprintf(filename, 50, "%s/%d", working_dir, i);
			unlink(filename);
			fd = open(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
			if (fd >= 0)
				close(fd);
		}
		sleep(2);
	}

	/* cleanup all files on exit */
	for (i = 0; i < num_adder_threads; i++) {
		snprintf(filename, 50, "%s/%d", working_dir, i);
		unlink(filename);
	}

	return NULL;
}

static int start_file_creater_threads(void)
{
	int rc;
	unsigned int i;

	file_creaters = calloc(num_file_creaters, sizeof(*file_creaters));
	if (!file_creaters)
		handle_error("allocating file creater pthreads");

	/* create threads which unlink and then recreate all of the files in question */
	for (i = 0; i < num_file_creaters; i++) {
		rc = pthread_create(&file_creaters[i], &attr, __create_files, NULL);
		if (rc)
			handle_error("creating the file creater threads");
		WAIT_CHILD;
	}
	return 0;
}

/* Reset the low_wd so removers can be smart */
static void *__reset_low_wd(__attribute__ ((unused)) void *ptr)
{
	fprintf(stdout, "Starting low_wd reset thread\n");

	WAKE_PARENT;

	while (!stopped) {
		low_wd = INT_MAX;
		sleep(1);
	}

	return NULL;
}

static int start_reset_low_wd_thread(void)
{
	int rc;

	/* create a thread that does nothing but reset the low_wd */
	rc = pthread_create(&low_wd_reseter, &attr, __reset_low_wd, NULL);
	if (rc)
		handle_error("low_wd_reseter");

	WAIT_CHILD;

	return 0;
}

/* Pull events off the buffer and ignore them */
static void *__dump_data(void *ptr)
{
	char buf[8096];
	struct operator_struct *operator_arg = ptr;
	int inotify_fd = operator_arg->inotify_fd;
	int ret;

	fprintf(stdout, "Starting inotify data dumper thread\n");

	WAKE_PARENT;

	while (!stopped) {
		ret = read(inotify_fd, buf, 8096);
		if (ret <= 0)
			pthread_yield();
	}

	return NULL;
}

/* create threads which just pull data off of the inotify fd. */
static int start_data_dumping_threads(struct thread_data *td)
{
	struct operator_struct os;
	unsigned int i;
	int rc;
	pthread_t *data_dumpers;

	os.inotify_fd = td->inotify_fd;

	/* allocate the pthread_t's for all of the threads */
	data_dumpers = calloc(num_data_dumpers, sizeof(*data_dumpers));
	if (!data_dumpers)
		handle_error("allocating data_dumpers");
	td->data_dumpers = data_dumpers;

	/* use default ATTR for larger stack */
	for (i = 0; i < num_data_dumpers; i++) {
		rc = pthread_create(&data_dumpers[i], NULL, __dump_data, &os);
		if (rc)
			handle_error("creating threads to dump inotify data");
		WAIT_CHILD;
	}
	return 0;
}

/* add a watch to a specific file as fast as we can */
static void *__add_watches(void *ptr)
{
	struct adder_struct *adder_arg = ptr;
	int file_num = adder_arg->file_num;
	int notify_fd = adder_arg->inotify_fd;
	int ret;
	char filename[50];

	fprintf(stdout, "Creating a watch creater thread, notify_fd=%d filenum=%d\n",
		notify_fd, file_num);

	snprintf(filename, 50, "%s/%d", working_dir, file_num);

	WAKE_PARENT;

	while (!stopped) {
		ret = inotify_add_watch(notify_fd, filename, IN_ALL_EVENTS);
		if (ret < 0 && errno != ENOENT)
			perror("inotify_add_watch");
		if (ret > high_wd)
			high_wd = ret;
		if (ret < low_wd)
			low_wd = ret;
		pthread_yield();
	}

	return NULL;
}

static int start_watch_creation_threads(struct thread_data *td)
{
	struct adder_struct ws;
	unsigned int i, j;
	int rc;
	pthread_t *adders;

	ws.inotify_fd = td->inotify_fd;

	/* allocate the pthread_t's for all of the threads */
	adders = calloc(num_adder_threads * watcher_multiplier, sizeof(*adders));
	if (!adders)
		handle_error("allocating adders");
	td->adders = adders;

	for (i = 0; i < num_adder_threads; i++) {
		ws.file_num = i;
		for (j = 0; j < watcher_multiplier; j++) {
			rc = pthread_create(&adders[i * watcher_multiplier + j], &attr, __add_watches, &ws);
			if (rc)
				handle_error("creating water threads");
			WAIT_CHILD;
		}
	}

	return 0;
}

/* run from low_wd to high_wd removing all watches in between */
static void *__remove_watches(void *ptr)
{
	struct operator_struct *operator_arg = ptr;
	int inotify_fd = operator_arg->inotify_fd;
	int i;

	fprintf(stdout, "Starting a thread to remove watches\n");

	WAKE_PARENT;

	while (!stopped) {
		for (i = low_wd; i < high_wd; i++)
			inotify_rm_watch(inotify_fd, i);
		pthread_yield();
	}
	return NULL;
}

static int start_watch_removal_threads(struct thread_data *td)
{
	struct operator_struct os;
	int rc;
	unsigned int i, j;
	pthread_t *removers;

	os.inotify_fd = td->inotify_fd;

	/* allocate the pthread_t's for all of the threads */
	removers = calloc(num_remover_threads * watcher_multiplier, sizeof(*removers));
	if (!removers)
		handle_error("allocating removal pthreads");

	td->removers = removers;

	/* create threads which walk from low_wd to high_wd closing all of the wd's in between */
	for (i = 0; i < num_remover_threads; i++) {
		for (j = 0; j < watcher_multiplier; j++) {
			rc = pthread_create(&removers[i * watcher_multiplier + j], &attr, __remove_watches, &os);
			if (rc)
				handle_error("creating the removal threads");
			WAIT_CHILD;
		}
	}
	return 0;
}

/* run from low_wd to low_wd+3 closing all watch in between just for extra races */
static void *__remove_lownum_watches(void *ptr)
{
	struct operator_struct *operator_arg = ptr;
	int inotify_fd = operator_arg->inotify_fd;
	int i;

	fprintf(stdout, "Starting thread to remove low watches\n");

	WAKE_PARENT;

	while (!stopped) {
		for (i = low_wd; i <= low_wd+3; i++)
			inotify_rm_watch(inotify_fd, i);
		pthread_yield();
	}
	return NULL;
}

static int start_lownum_watch_removal_threads(struct thread_data *td)
{
	struct operator_struct od;
	int rc;
	unsigned int i;
	pthread_t *lownum_removers;

	od.inotify_fd = td->inotify_fd;

	lownum_removers = calloc(num_low_remover_threads, sizeof(*lownum_removers));
	if (!lownum_removers)
		handle_error("allocating lownum removal pthreads");

	td->lownum_removers = lownum_removers;

	/* create threads which walk from low_wd to high_wd closing all of the wd's in between */
	for (i = 0; i < num_low_remover_threads; i++) {
		rc = pthread_create (&lownum_removers[i], &attr, __remove_lownum_watches, &od);
		if (rc)
			handle_error("creating the lownum removal threads");
		WAIT_CHILD;
	}
	return 0;
}

static void *__mount_fs(__attribute__ ((unused)) void *ptr)
{
	int rc;
 
	fprintf(stdout, "Starting mount and unmount fs on top of working dir\n");

	WAKE_PARENT;

	while (!stopped) {
		rc = mount(mnt_src, working_dir, fstype, MS_MGC_VAL, "rootcontext=\"unconfined_u:object_r:tmp_t:s0\"");
		usleep(100000);
		if (!rc)
			umount2(working_dir, MNT_DETACH);
		else
			fprintf(stderr, "Failed to mount %s: %s\n", mnt_src, strerror(errno));
		usleep(100000);
	}
	return NULL;
}

static int start_mount_fs_thread(void)
{
	int rc;

	rc = pthread_create(&mounter, &attr, __mount_fs, NULL);
	if (rc)
		handle_error("creating the thread to mount and unmount an fs");
	WAIT_CHILD;

	return 0;
}

static int join_threads(struct thread_data *td)
{
	unsigned int i, j;
	void *ret;
	pthread_t *to_join;

	to_join = td->adders;
	for (i = 0; i < num_adder_threads; i++)
		for (j = 0; j < watcher_multiplier; j++)
			pthread_join(to_join[i * watcher_multiplier + j], &ret);

	to_join = td->removers;
	for (i = 0; i < num_remover_threads; i++)
		for (j = 0; j < watcher_multiplier; j++)
			pthread_join(to_join[i * watcher_multiplier + j], &ret);

	to_join = td->lownum_removers;
	for (i = 0; i < num_low_remover_threads; i++)
		pthread_join(to_join[i], &ret);

	to_join = td->data_dumpers;
	for (i = 0; i < num_data_dumpers; i++)
		pthread_join(to_join[i], &ret);

	return 0;
}

static int str_to_uint(unsigned int *out, char *in)
{
	long val;
	char *endptr;

	errno = 0;    /* To distinguish success/failure after call */
	val = strtol(in, &endptr, 10);

	/* Check for various possible errors */
	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
		perror("strtol");
		return -1;
	}

	if (endptr == in) {
		fprintf(stderr, "No digits were found\n");
		return -1;
	}

	if (*endptr != '\0') { /* random shit after the number? */
		printf("Further characters after number: %s\n", endptr);
		return -1;
	}

	*out = val;

	return 0;
}

static int process_args(int argc, char *argv[])
{
	int c;

	while (1) {
		int option_index = 0;
		static struct option long_options[] = {
		    {"cores",	required_argument,	0, 'c'},
		    {"data",	required_argument,	0, 'd'},
		    {"multiplier", required_argument,	0, 'm'},
		    {"low",	required_argument,	0, 'l'},
		    {"adders", required_argument,	0, 'a'},
		    {"instances", required_argument,	0, 'i'},
		    {"dir", required_argument,		0, 't'},
		    {"source_mnt", required_argument,	0, 's'},
		    {"fstype", required_argument,	0, 'f'},
		    {0,		0,			0,  0 }
		};

		c = getopt_long(argc, argv, "c:d:m:z:r:i:t:s:f:", long_options, &option_index);
		if (c == -1)
			break;

		switch (c) {
		case 'c':
			str_to_uint(&num_cores, optarg);
			break;
		case 'd':
			str_to_uint(&num_data_dumpers, optarg);
			break;
		case 'm':
			str_to_uint(&watcher_multiplier, optarg);
			break;
		case 'l':
			str_to_uint(&num_low_remover_threads, optarg);
			break;
		case 'a':
			str_to_uint(&num_adder_threads, optarg);
			break;
		case 'i':
			str_to_uint(&num_cores, optarg);
			break;
		case 't':
			working_dir = optarg;
			break;
		case 's':
			mnt_src = optarg;
			break;
		case 'f':
			fstype = optarg;
			break;
		default:
			printf("?? unknown option 0%o ??\n", c);
			return -1;
		}
	}

	if (optind < argc) {
		printf("non-option ARGV-elements: ");
		while (optind < argc)
			printf("%s ", argv[optind++]);
		printf("\n");
	}

	if (num_cores == 0)
		num_cores = sysconf(_SC_NPROCESSORS_ONLN);
	if (num_cores < 1)
		num_cores = 1;
	num_cores++;

	if (num_data_dumpers == 0)
		num_data_dumpers = 1;

	if (watcher_multiplier == 0)
		watcher_multiplier = 2;

	if (num_low_remover_threads == 0)
		num_low_remover_threads = 1;

	if (num_file_creaters == 0)
		num_file_creaters = num_cores/2;

	if (num_inotify_instances == 0)
		num_inotify_instances = num_cores/2;

	if (mnt_src == NULL)
		mnt_src = working_dir;

	if (num_adder_threads == 0)
		num_adder_threads = 3;

	if (num_remover_threads == 0)
		num_remover_threads = num_adder_threads;

	return 0;
}

int main(int argc, char *argv[])
{
	struct thread_data *td;
	int rc;
	void *ret;
	unsigned int i;
	struct sigaction setmask;

	rc = process_args(argc, argv);
	if (rc)
		handle_error("processing arguments");

	/* close cleanly on cntl+c */
	sigemptyset( &setmask.sa_mask );
	setmask.sa_handler = sigfunc;
	setmask.sa_flags   = 0;
	sigaction( SIGINT,  &setmask, (struct sigaction *) NULL );

	/* make sure the directory exists */
	mkdir(working_dir, S_IRWXU);

	/* set up a pthread attr with a tiny stack */
	rc = pthread_attr_init(&attr);
	if (rc)
		handle_error("pthread_attr_init");
	rc = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN*2);
	if (rc)
		handle_error("pthread_attr_setstacksize");

	td = calloc(num_inotify_instances, sizeof(*td));
	if (!td)
		handle_error("allocating inotify td array");

	/* create an inotify instance and make it O_NONBLOCK */
	for (i = 0; i < num_inotify_instances; i++) {
		struct thread_data *t;
		int fd;

		fd = inotify_init1(O_NONBLOCK);
		if (fd < 0)
			handle_error("opening inotify_fd");

		t = &td[i];
		t->inotify_fd = fd;

		rc = start_watch_creation_threads(t);
		if (rc)
			handle_error("creating watch adding threads");

		rc = start_watch_removal_threads(t);
		if (rc)
			handle_error("creating watch remover threads");

		rc = start_lownum_watch_removal_threads(t);
		if (rc)
			handle_error("creating lownum watch remover threads");

		rc = start_data_dumping_threads(t);
		if (rc)
			handle_error("creating data dumping threads");
	}

	rc = start_file_creater_threads();
	if (rc)
		handle_error("creating file creation/rm threads");

	rc = start_reset_low_wd_thread();
	if (rc)
		handle_error("starting thread to reset the low_wd");

	rc = start_mount_fs_thread();
	if (rc)
		handle_error("starting mounting thread");

	/* join the per inotify instance threads */
	for (i = 0; i < num_inotify_instances; i++)
		join_threads(&td[i]);

	for (i = 0; i < num_file_creaters; i++)
		pthread_join(file_creaters[i], &ret);

	pthread_join(low_wd_reseter, &ret);
	pthread_join(mounter, &ret);

	/* clean up the tmp dir which should be empty */
	rmdir(working_dir);

	for (i = 0; i < num_inotify_instances; i++) {
		free(td[i].adders);
		free(td[i].removers);
		free(td[i].lownum_removers);
		free(td[i].data_dumpers);
	}
	free(td);
	free(file_creaters);
	exit(EXIT_SUCCESS);
}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [GIT PULL] notification tree changes for 3.8
  2012-12-21  2:49   ` Eric Paris
@ 2012-12-21  4:00     ` Linus Torvalds
  0 siblings, 0 replies; 4+ messages in thread
From: Linus Torvalds @ 2012-12-21  4:00 UTC (permalink / raw)
  To: Eric Paris; +Cc: Lino Sanfilippo, Linux Kernel Mailing List

On Thu, Dec 20, 2012 at 6:49 PM, Eric Paris <eparis@redhat.com> wrote:
>
> It is a locking change, but if anything goes wrong, at least I've got
> time without other work commitments over the next 2 weeks to fix them.

That doesn't much help. Because realistically, very few people will be
*testing* over the next two weeks.

Grr.

Ok, so I'll pull, but dammit, this kind of crap has got to stop.
There's *no* reason to start rebasing when the merge window opens, and
then leave it to the last day. Seriously. This bugs the hell out of
me.

            Linus

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-12-21  4:00 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-20 22:38 [GIT PULL] notification tree changes for 3.8 Eric Paris
2012-12-21  1:50 ` Linus Torvalds
2012-12-21  2:49   ` Eric Paris
2012-12-21  4:00     ` Linus Torvalds

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).