X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..0c530ab8987f0ae6a1a3d9284f40182b88852816:/bsd/vfs/vfs_fsevents.c diff --git a/bsd/vfs/vfs_fsevents.c b/bsd/vfs/vfs_fsevents.c index d3eed8126..801faa3c1 100644 --- a/bsd/vfs/vfs_fsevents.c +++ b/bsd/vfs/vfs_fsevents.c @@ -1,31 +1,23 @@ /* - * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, unlawful or unlicensed copies of an Apple operating - * system, or to circumvent, violate, or enable the circumvention or - * violation of, any terms of an Apple operating system software license - * agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ */ #include #include @@ -49,7 +41,6 @@ #include #include #include -#include #include #include @@ -96,6 +87,7 @@ typedef struct fs_event_watcher { int32_t eventq_size; // number of event pointers in queue int32_t rd, wr; // indices to the event_queue int32_t blockers; + int32_t num_readers; } fs_event_watcher; // fs_event_watcher flags @@ -257,7 +249,7 @@ add_fsevent(int type, vfs_context_t ctx, ...) kfs_event *kfse; fs_event_watcher *watcher; va_list ap; - int error = 0; + int error = 0, base; dev_t dev = 0; va_start(ap, ctx); @@ -275,8 +267,9 @@ add_fsevent(int type, vfs_context_t ctx, ...) // the lock is dropped. lock_fs_event_buf(); + base = free_event_idx; for(i=0; i < MAX_KFS_EVENTS; i++) { - if (fs_event_buf[(free_event_idx + i) % MAX_KFS_EVENTS].type == FSE_INVALID) { + if (fs_event_buf[(base + i) % MAX_KFS_EVENTS].type == FSE_INVALID) { break; } } @@ -298,12 +291,12 @@ add_fsevent(int type, vfs_context_t ctx, ...) return ENOSPC; } - kfse = &fs_event_buf[(free_event_idx + i) % MAX_KFS_EVENTS]; + kfse = &fs_event_buf[(base + i) % MAX_KFS_EVENTS]; - free_event_idx++; + free_event_idx = ((base + i) % MAX_KFS_EVENTS) + 1; kfse->type = type; - kfse->refcount = 0; + kfse->refcount = 1; kfse->pid = p->p_pid; unlock_fs_event_buf(); // at this point it's safe to unlock @@ -470,9 +463,8 @@ add_fsevent(int type, vfs_context_t ctx, ...) clean_up: // just in case no one was interested after all... - if (num_deliveries == 0) { + if (OSAddAtomic(-1, (SInt32 *)&kfse->refcount) == 1) { do_free_event(kfse); - free_event_idx = (int)(kfse - &fs_event_buf[0]); } lck_rw_done(&fsevent_big_lock); @@ -487,8 +479,10 @@ do_free_event(kfs_event *kfse) lock_fs_event_buf(); - // mark this fsevent as invalid - kfse->type = FSE_INVALID; + if (kfse->refcount > 0) { + panic("do_free_event: free'ing a kfsevent w/refcount == %d (kfse %p)\n", + kfse->refcount, kfse); + } // make a copy of this so we can free things without // holding the fs_event_buf lock @@ -498,6 +492,9 @@ do_free_event(kfs_event *kfse) // and just to be anal, set this so that there are no args kfse->args[0].type = FSE_ARG_DONE; + // mark this fsevent as invalid + kfse->type = FSE_INVALID; + free_event_idx = (kfse - fs_event_buf); unlock_fs_event_buf(); @@ -550,6 +547,7 @@ add_watcher(int8_t *event_list, int32_t num_events, int32_t eventq_size, fs_even watcher->rd = 0; watcher->wr = 0; watcher->blockers = 0; + watcher->num_readers = 0; lock_watch_list(); @@ -658,9 +656,15 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio) return EINVAL; } + if (OSAddAtomic(1, (SInt32 *)&watcher->num_readers) != 0) { + // don't allow multiple threads to read from the fd at the same time + OSAddAtomic(-1, (SInt32 *)&watcher->num_readers); + return EAGAIN; + } if (watcher->rd == watcher->wr) { if (watcher->flags & WATCHER_CLOSING) { + OSAddAtomic(-1, (SInt32 *)&watcher->num_readers); return 0; } OSAddAtomic(1, (SInt32 *)&watcher->blockers); @@ -671,6 +675,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio) OSAddAtomic(-1, (SInt32 *)&watcher->blockers); if (error != 0 || (watcher->flags & WATCHER_CLOSING)) { + OSAddAtomic(-1, (SInt32 *)&watcher->num_readers); return error; } } @@ -689,6 +694,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio) } if (error) { + OSAddAtomic(-1, (SInt32 *)&watcher->num_readers); return error; } @@ -858,6 +864,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio) } get_out: + OSAddAtomic(-1, (SInt32 *)&watcher->num_readers); return error; } @@ -910,6 +917,9 @@ fsevent_unmount(struct mount *mp) if (vname) vnode_putname(vname); + + strcpy(pathbuff, "UNKNOWN-FILE"); + pathbuff_len = strlen(pathbuff) + 1; } // switch the type of the string @@ -936,10 +946,13 @@ static int fsevents_installed = 0; static struct lock__bsd__ fsevents_lck; typedef struct fsevent_handle { + UInt32 flags; + SInt32 active; fs_event_watcher *watcher; struct selinfo si; } fsevent_handle; +#define FSEH_CLOSING 0x0001 static int fseventsf_read(struct fileproc *fp, struct uio *uio, @@ -971,15 +984,27 @@ fseventsf_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, struct proc *p) pid_t pid = 0; fsevent_dev_filter_args *devfilt_args=(fsevent_dev_filter_args *)data; + OSAddAtomic(1, &fseh->active); + if (fseh->flags & FSEH_CLOSING) { + OSAddAtomic(-1, &fseh->active); + return 0; + } + switch (cmd) { case FIONBIO: case FIOASYNC: - return 0; + ret = 0; + break; case FSEVENTS_DEVICE_FILTER: { int new_num_devices; dev_t *devices_to_watch, *tmp=NULL; + if (fseh->flags & FSEH_CLOSING) { + ret = 0; + break; + } + if (devfilt_args->num_devices > 256) { ret = EINVAL; break; @@ -1034,6 +1059,7 @@ fseventsf_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, struct proc *p) break; } + OSAddAtomic(-1, &fseh->active); return (ret); } @@ -1075,11 +1101,18 @@ static int fseventsf_close(struct fileglob *fg, struct proc *p) { fsevent_handle *fseh = (struct fsevent_handle *)fg->fg_data; + fs_event_watcher *watcher; + + OSBitOrAtomic(FSEH_CLOSING, &fseh->flags); + while (OSAddAtomic(0, &fseh->active) > 0) { + tsleep((caddr_t)fseh->watcher, PRIBIO, "fsevents-close", 1); + } - remove_watcher(fseh->watcher); - - fg->fg_data = NULL; + watcher = fseh->watcher; fseh->watcher = NULL; + fg->fg_data = NULL; + + remove_watcher(watcher); FREE(fseh, M_TEMP); return 0; @@ -1218,7 +1251,7 @@ fseventsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) proc_fdunlock(p); copyout((void *)&fd, CAST_USER_ADDR_T(fse_clone_args->fd), sizeof(int32_t)); proc_fdlock(p); - *fdflags(p, fd) &= ~UF_RESERVED; + procfdtbl_releasefd(p, fd, NULL); fp_drop(p, fd, f, 1); proc_fdunlock(p); break;