X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d26ffc64f583ab2d29df48f13518685602bc8832..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/vfs/vfs_syscalls.c diff --git a/bsd/vfs/vfs_syscalls.c b/bsd/vfs/vfs_syscalls.c index dccc77bd6..767d352c6 100644 --- a/bsd/vfs/vfs_syscalls.c +++ b/bsd/vfs/vfs_syscalls.c @@ -174,8 +174,6 @@ static int getfsstat_callback(mount_t mp, void * arg); static int getutimes(user_addr_t usrtvp, struct timespec *tsp); static int setutimes(vfs_context_t ctx, vnode_t vp, const struct timespec *ts, int nullflag); static int sync_callback(mount_t, void *); -static void hibernate_sync_thread(void *, __unused wait_result_t); -static int hibernate_sync_async(int); static int munge_statfs(struct mount *mp, struct vfsstatfs *sfsp, user_addr_t bufp, int *sizep, boolean_t is_64_bit, boolean_t partial_copy); @@ -217,6 +215,13 @@ static void mount_end_update(mount_t mp); static int relocate_imageboot_source(vnode_t pvp, vnode_t vp, struct componentname *cnp, const char *fsname, vfs_context_t ctx, boolean_t is64bit, user_addr_t fsmountargs, boolean_t by_index); #endif /* CONFIG_IMGSRC_ACCESS */ +//snapshot functions +#if CONFIG_MNT_ROOTSNAP +static int snapshot_root(int dirfd, user_addr_t name, uint32_t flags, vfs_context_t ctx); +#else +static int snapshot_root(int dirfd, user_addr_t name, uint32_t flags, vfs_context_t ctx) __attribute__((unused)); +#endif + int (*union_dircheckp)(struct vnode **, struct fileproc *, vfs_context_t); __private_extern__ @@ -2323,8 +2328,6 @@ int syncprt = 0; #endif int print_vmpage_stat=0; -int sync_timeout = 60; // Sync time limit (sec) - static int sync_callback(mount_t mp, __unused void *arg) @@ -2358,15 +2361,64 @@ sync(__unused proc_t p, __unused struct sync_args *uap, __unused int32_t *retval return 0; } +typedef enum { + SYNC_ALL = 0, + SYNC_ONLY_RELIABLE_MEDIA = 1, + SYNC_ONLY_UNRELIABLE_MEDIA = 2 +} sync_type_t; + +static int +sync_internal_callback(mount_t mp, void *arg) +{ + if (arg) { + int is_reliable = !(mp->mnt_kern_flag & MNTK_VIRTUALDEV) && + (mp->mnt_flag & MNT_LOCAL); + sync_type_t sync_type = *((sync_type_t *)arg); + + if ((sync_type == SYNC_ONLY_RELIABLE_MEDIA) && !is_reliable) + return (VFS_RETURNED); + else if ((sync_type = SYNC_ONLY_UNRELIABLE_MEDIA) && is_reliable) + return (VFS_RETURNED); + } + + (void)sync_callback(mp, NULL); + + return (VFS_RETURNED); +} + +int sync_thread_state = 0; +int sync_timeout_seconds = 5; + +#define SYNC_THREAD_RUN 0x0001 +#define SYNC_THREAD_RUNNING 0x0002 + static void -hibernate_sync_thread(void *arg, __unused wait_result_t wr) +sync_thread(__unused void *arg, __unused wait_result_t wr) { - int *timeout = (int *) arg; + sync_type_t sync_type; - vfs_iterate(LK_NOWAIT, sync_callback, NULL); + lck_mtx_lock(sync_mtx_lck); + while (sync_thread_state & SYNC_THREAD_RUN) { + sync_thread_state &= ~SYNC_THREAD_RUN; + lck_mtx_unlock(sync_mtx_lck); + + sync_type = SYNC_ONLY_RELIABLE_MEDIA; + vfs_iterate(LK_NOWAIT, sync_internal_callback, &sync_type); + sync_type = SYNC_ONLY_UNRELIABLE_MEDIA; + vfs_iterate(LK_NOWAIT, sync_internal_callback, &sync_type); + + lck_mtx_lock(sync_mtx_lck); + } + /* + * This wakeup _has_ to be issued before the lock is released otherwise + * we may end up waking up a thread in sync_internal which is + * expecting a wakeup from a thread it just created and not from this + * thread which is about to exit. + */ + wakeup(&sync_thread_state); + sync_thread_state &= ~SYNC_THREAD_RUNNING; + lck_mtx_unlock(sync_mtx_lck); - if (timeout) - wakeup((caddr_t) timeout); if (print_vmpage_stat) { vm_countdirtypages(); } @@ -2377,41 +2429,52 @@ hibernate_sync_thread(void *arg, __unused wait_result_t wr) #endif /* DIAGNOSTIC */ } +struct timeval sync_timeout_last_print = {0, 0}; + /* - * Sync in a separate thread so we can time out if it blocks. + * An in-kernel sync for power management to call. + * This function always returns within sync_timeout seconds. */ -static int -hibernate_sync_async(int timeout) +__private_extern__ int +sync_internal(void) { thread_t thd; int error; - struct timespec ts = {timeout, 0}; + int thread_created = FALSE; + struct timespec ts = {sync_timeout_seconds, 0}; lck_mtx_lock(sync_mtx_lck); - if (kernel_thread_start(hibernate_sync_thread, &timeout, &thd) != KERN_SUCCESS) { - printf("hibernate_sync_thread failed\n"); - lck_mtx_unlock(sync_mtx_lck); - return (0); + sync_thread_state |= SYNC_THREAD_RUN; + if (!(sync_thread_state & SYNC_THREAD_RUNNING)) { + int kr; + + sync_thread_state |= SYNC_THREAD_RUNNING; + kr = kernel_thread_start(sync_thread, NULL, &thd); + if (kr != KERN_SUCCESS) { + sync_thread_state &= ~SYNC_THREAD_RUNNING; + lck_mtx_unlock(sync_mtx_lck); + printf("sync_thread failed\n"); + return (0); + } + thread_created = TRUE; } - error = msleep((caddr_t) &timeout, sync_mtx_lck, (PVFS | PDROP | PCATCH), "hibernate_sync_thread", &ts); + error = msleep((caddr_t)&sync_thread_state, sync_mtx_lck, + (PVFS | PDROP | PCATCH), "sync_thread", &ts); if (error) { - printf("sync timed out: %d sec\n", timeout); + struct timeval now; + + microtime(&now); + if (now.tv_sec - sync_timeout_last_print.tv_sec > 120) { + printf("sync timed out: %d sec\n", sync_timeout_seconds); + sync_timeout_last_print.tv_sec = now.tv_sec; + } } - thread_deallocate(thd); - return (0); -} + if (thread_created) + thread_deallocate(thd); -/* - * An in-kernel sync for power management to call. - */ -__private_extern__ int -sync_internal(void) -{ - (void) hibernate_sync_async(sync_timeout); - - return 0; + return (0); } /* end of sync_internal call */ /* @@ -2422,12 +2485,12 @@ int quotactl(proc_t p, struct quotactl_args *uap, __unused int32_t *retval) { struct mount *mp; - int error, quota_cmd, quota_status; + int error, quota_cmd, quota_status = 0; caddr_t datap; size_t fnamelen; struct nameidata nd; vfs_context_t ctx = vfs_context_current(); - struct dqblk my_dqblk; + struct dqblk my_dqblk = {}; AUDIT_ARG(uid, uap->uid); AUDIT_ARG(cmd, uap->cmd); @@ -3646,6 +3709,12 @@ open1(vfs_context_t ctx, struct nameidata *ndp, int uflags, strlen(vp->v_name)) || !strncmp(vp->v_name, "mediaserverd", + strlen(vp->v_name)) || + !strncmp(vp->v_name, + "SpringBoard", + strlen(vp->v_name)) || + !strncmp(vp->v_name, + "backboardd", strlen(vp->v_name))) { /* * This file matters when launching Camera: @@ -5294,7 +5363,7 @@ access_extended(__unused proc_t p, struct access_extended_args *uap, __unused in error = ENOMEM; goto out; } - MALLOC(result, errno_t *, desc_actual * sizeof(errno_t), M_TEMP, M_WAITOK); + MALLOC(result, errno_t *, desc_actual * sizeof(errno_t), M_TEMP, M_WAITOK | M_ZERO); if (result == NULL) { error = ENOMEM; goto out; @@ -7340,6 +7409,57 @@ continue_lookup: } batched = vnode_compound_rename_available(fdvp); + +#if CONFIG_FSE + need_event = need_fsevent(FSE_RENAME, fdvp); + if (need_event) { + if (fvp) { + get_fse_info(fvp, &from_finfo, ctx); + } else { + error = vfs_get_notify_attributes(&__rename_data->fv_attr); + if (error) { + goto out1; + } + + fvap = &__rename_data->fv_attr; + } + + if (tvp) { + get_fse_info(tvp, &to_finfo, ctx); + } else if (batched) { + error = vfs_get_notify_attributes(&__rename_data->tv_attr); + if (error) { + goto out1; + } + + tvap = &__rename_data->tv_attr; + } + } +#else + need_event = 0; +#endif /* CONFIG_FSE */ + + if (need_event || kauth_authorize_fileop_has_listeners()) { + if (from_name == NULL) { + GET_PATH(from_name); + if (from_name == NULL) { + error = ENOMEM; + goto out1; + } + } + + from_len = safe_getpath(fdvp, fromnd->ni_cnd.cn_nameptr, from_name, MAXPATHLEN, &from_truncated); + + if (to_name == NULL) { + GET_PATH(to_name); + if (to_name == NULL) { + error = ENOMEM; + goto out1; + } + } + + to_len = safe_getpath(tdvp, tond->ni_cnd.cn_nameptr, to_name, MAXPATHLEN, &to_truncated); + } if (!fvp) { /* * Claim: this check will never reject a valid rename. @@ -7359,7 +7479,7 @@ continue_lookup: } if (!batched) { - error = vn_authorize_renamex(fdvp, fvp, &fromnd->ni_cnd, tdvp, tvp, &tond->ni_cnd, ctx, flags, NULL); + error = vn_authorize_renamex_with_paths(fdvp, fvp, &fromnd->ni_cnd, from_name, tdvp, tvp, &tond->ni_cnd, to_name, ctx, flags, NULL); if (error) { if (error == ENOENT) { assert(retry_count < MAX_AUTHORIZE_ENOENT_RETRIES); @@ -7550,56 +7670,6 @@ continue_lookup: oparent = fvp->v_parent; skipped_lookup: -#if CONFIG_FSE - need_event = need_fsevent(FSE_RENAME, fdvp); - if (need_event) { - if (fvp) { - get_fse_info(fvp, &from_finfo, ctx); - } else { - error = vfs_get_notify_attributes(&__rename_data->fv_attr); - if (error) { - goto out1; - } - - fvap = &__rename_data->fv_attr; - } - - if (tvp) { - get_fse_info(tvp, &to_finfo, ctx); - } else if (batched) { - error = vfs_get_notify_attributes(&__rename_data->tv_attr); - if (error) { - goto out1; - } - - tvap = &__rename_data->tv_attr; - } - } -#else - need_event = 0; -#endif /* CONFIG_FSE */ - - if (need_event || kauth_authorize_fileop_has_listeners()) { - if (from_name == NULL) { - GET_PATH(from_name); - if (from_name == NULL) { - error = ENOMEM; - goto out1; - } - } - - from_len = safe_getpath(fdvp, fromnd->ni_cnd.cn_nameptr, from_name, MAXPATHLEN, &from_truncated); - - if (to_name == NULL) { - GET_PATH(to_name); - if (to_name == NULL) { - error = ENOMEM; - goto out1; - } - } - - to_len = safe_getpath(tdvp, tond->ni_cnd.cn_nameptr, to_name, MAXPATHLEN, &to_truncated); - } error = vn_rename(fdvp, &fvp, &fromnd->ni_cnd, fvap, tdvp, &tvp, &tond->ni_cnd, tvap, flags, ctx); @@ -8658,10 +8728,10 @@ getdirentriesattr (proc_t p, struct getdirentriesattr_args *uap, int32_t *retval struct fileproc *fp; uio_t auio = NULL; int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32; - uint32_t count, savecount; - uint32_t newstate; + uint32_t count = 0, savecount = 0; + uint32_t newstate = 0; int error, eofflag; - uint32_t loff; + uint32_t loff = 0; struct attrlist attributelist; vfs_context_t ctx = vfs_context_current(); int fd = uap->fd; @@ -10613,7 +10683,8 @@ getxattr(proc_t p, struct getxattr_args *uap, user_ssize_t *retval) vp = nd.ni_vp; nameidone(&nd); - if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) { + error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen); + if (error != 0) { goto out; } if (xattr_protected(attrname)) { @@ -10693,7 +10764,8 @@ fgetxattr(proc_t p, struct fgetxattr_args *uap, user_ssize_t *retval) file_drop(uap->fd); return(error); } - if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) { + error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen); + if (error != 0) { goto out; } if (xattr_protected(attrname)) { @@ -10739,7 +10811,8 @@ setxattr(proc_t p, struct setxattr_args *uap, int *retval) if (uap->options & (XATTR_NOSECURITY | XATTR_NODEFAULT)) return (EINVAL); - if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) { + error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen); + if (error != 0) { if (error == EPERM) { /* if the string won't fit in attrname, copyinstr emits EPERM */ return (ENAMETOOLONG); @@ -10798,7 +10871,8 @@ fsetxattr(proc_t p, struct fsetxattr_args *uap, int *retval) if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY | XATTR_NODEFAULT)) return (EINVAL); - if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) { + error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen); + if (error != 0) { if (error == EPERM) { /* if the string won't fit in attrname, copyinstr emits EPERM */ return (ENAMETOOLONG); @@ -11096,9 +11170,9 @@ unionget: if (kdebug_enable) { long dbg_parms[NUMPARMS]; - int dbg_namelen; + int dbg_namelen; - dbg_namelen = (int)sizeof(dbg_parms); + dbg_namelen = (int)sizeof(dbg_parms); if (length < dbg_namelen) { memcpy((char *)dbg_parms, buf, length); @@ -11109,7 +11183,8 @@ unionget: memcpy((char *)dbg_parms, buf + (length - dbg_namelen), dbg_namelen); } - kdebug_lookup_gen_events(dbg_parms, dbg_namelen, (void *)vp, TRUE); + kdebug_vfs_lookup(dbg_parms, dbg_namelen, (void *)vp, + KDBG_VFS_LOOKUP_FLAG_LOOKUP); } *pathlen = (user_ssize_t)length; /* may be superseded by error */ @@ -11140,7 +11215,7 @@ fsgetpath(__unused proc_t p, struct fsgetpath_args *uap, user_ssize_t *retval) if (uap->bufsize > PAGE_SIZE) { return (EINVAL); } - MALLOC(realpath, char *, uap->bufsize, M_TEMP, M_WAITOK); + MALLOC(realpath, char *, uap->bufsize, M_TEMP, M_WAITOK | M_ZERO); if (realpath == NULL) { return (ENOMEM); } @@ -12031,11 +12106,11 @@ fs_snapshot(__unused proc_t p, struct fs_snapshot_args *uap, case SNAPSHOT_OP_REVERT: error = snapshot_revert(uap->dirfd, uap->name1, uap->flags, ctx); break; -#if !TARGET_OS_OSX +#if CONFIG_MNT_ROOTSNAP case SNAPSHOT_OP_ROOT: error = snapshot_root(uap->dirfd, uap->name1, uap->flags, ctx); break; -#endif /* !TARGET_OS_OSX */ +#endif /* CONFIG_MNT_ROOTSNAP */ default: error = ENOSYS; }