Changeset View
Standalone View
sys/kern/uipc_shm.c
Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
#define SHM_HASH(fnv) (&shm_dictionary[(fnv) & shm_hash]) | #define SHM_HASH(fnv) (&shm_dictionary[(fnv) & shm_hash]) | ||||
static void shm_init(void *arg); | static void shm_init(void *arg); | ||||
static void shm_insert(char *path, Fnv32_t fnv, struct shmfd *shmfd); | static void shm_insert(char *path, Fnv32_t fnv, struct shmfd *shmfd); | ||||
static struct shmfd *shm_lookup(char *path, Fnv32_t fnv); | static struct shmfd *shm_lookup(char *path, Fnv32_t fnv); | ||||
static int shm_remove(char *path, Fnv32_t fnv, struct ucred *ucred); | static int shm_remove(char *path, Fnv32_t fnv, struct ucred *ucred); | ||||
static int shm_dotruncate_locked(struct shmfd *shmfd, off_t length, | static int shm_dotruncate_locked(struct shmfd *shmfd, off_t length, | ||||
void *rl_cookie); | void *rl_cookie); | ||||
static int shm_copyin_path(struct thread *td, const char *userpath_in, | |||||
char **path_out); | |||||
static fo_rdwr_t shm_read; | static fo_rdwr_t shm_read; | ||||
static fo_rdwr_t shm_write; | static fo_rdwr_t shm_write; | ||||
static fo_truncate_t shm_truncate; | static fo_truncate_t shm_truncate; | ||||
static fo_ioctl_t shm_ioctl; | static fo_ioctl_t shm_ioctl; | ||||
static fo_stat_t shm_stat; | static fo_stat_t shm_stat; | ||||
static fo_close_t shm_close; | static fo_close_t shm_close; | ||||
static fo_chmod_t shm_chmod; | static fo_chmod_t shm_chmod; | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
shmfd = fp->f_data; | shmfd = fp->f_data; | ||||
fp->f_data = NULL; | fp->f_data = NULL; | ||||
shm_drop(shmfd); | shm_drop(shmfd); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
shm_copyin_path(struct thread *td, const char *userpath_in, char **path_out) { | |||||
int error; | |||||
char *path; | |||||
const char *pr_path; | |||||
size_t pr_pathlen; | |||||
error = 0; | |||||
kib: No point in the assignment. | |||||
path = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK); | |||||
pr_path = td->td_ucred->cr_prison->pr_path; | |||||
Not Done Inline ActionsWe usually put the trailing binary (or ternary in this case) operator on the previous line. IOW, style prefers to keep ':' on the line 437. kib: We usually put the trailing binary (or ternary in this case) operator on the previous line. IOW… | |||||
Done Inline ActionsGood to know. I'll put the ternary line on a single line, breaking after '=='. matthew.bryan_isilon.com: Good to know. I'll put the ternary line on a single line, breaking after '=='. | |||||
/* Construct a full pathname for jailed callers. */ | |||||
pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 | |||||
: strlcpy(path, pr_path, MAXPATHLEN); | |||||
error = copyinstr(userpath_in, path + pr_pathlen, | |||||
MAXPATHLEN - pr_pathlen, NULL); | |||||
if (error != 0) | |||||
goto out; | |||||
#ifdef KTRACE | |||||
if (KTRPOINT(curthread, KTR_NAMEI)) | |||||
ktrnamei(path); | |||||
#endif | |||||
Done Inline ActionsIt is too late to check for '/' at the start of name for jailed case. I understand that previous code did the same, but this is not a reason to keep it. kib: It is too late to check for '/' at the start of name for jailed case. I understand that… | |||||
Done Inline ActionsCould you tell me what you are suggesting? In the jail case this is pointing to the char after the jail name to make sure there is a '/' there. Do we also need to check the first character? I don't know if pr_path always has a leading '/'. So are you suggesting this? if (path[pr_pathlen] != '/' || path[0] != '/') Or do you mean we shouldn't do this check at all in the jail case? Or only check the first character? matthew.bryan_isilon.com: Could you tell me what you are suggesting? In the jail case this is pointing to the char after… | |||||
Not Done Inline ActionsI do not remember the previous version of your patch, but the current code looks fine. I mean that the user-supplied path must start with '/'. Interesting but unrelated question is should we collapse multiple slashes into one. kib: I do not remember the previous version of your patch, but the current code looks fine. I mean… | |||||
/* Require paths to start with a '/' character. */ | |||||
if (path[pr_pathlen] != '/') { | |||||
error = EINVAL; | |||||
goto out; | |||||
Done Inline ActionsExtra blank line. kib: Extra blank line. | |||||
Done Inline ActionsHere and elsewhere: I'm leaving the blank lines for readability. matthew.bryan_isilon.com: Here and elsewhere: I'm leaving the blank lines for readability. | |||||
Not Done Inline ActionsUnneeded blank lines eat vertical space in editor. Style only suggests empty lines in very specific cases, like split between local vars and code block, or before/after multiline-commented block. kib: Unneeded blank lines eat vertical space in editor.
Style only suggests empty lines in very… | |||||
} | |||||
*path_out = path; | |||||
out: | |||||
if (error != 0) | |||||
Done Inline ActionsExtra blank line. kib: Extra blank line. | |||||
free(path, M_SHMFD); | |||||
return (error); | |||||
} | |||||
static int | |||||
shm_dotruncate_locked(struct shmfd *shmfd, off_t length, void *rl_cookie) | shm_dotruncate_locked(struct shmfd *shmfd, off_t length, void *rl_cookie) | ||||
{ | { | ||||
vm_object_t object; | vm_object_t object; | ||||
vm_page_t m; | vm_page_t m; | ||||
vm_pindex_t idx, nobjsize; | vm_pindex_t idx, nobjsize; | ||||
vm_ooffset_t delta; | vm_ooffset_t delta; | ||||
int base, rv; | int base, rv; | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
kern_shm_open(struct thread *td, const char *userpath, int flags, mode_t mode, | kern_shm_open(struct thread *td, const char *userpath, int flags, mode_t mode, | ||||
struct filecaps *fcaps, int initial_seals) | struct filecaps *fcaps, int initial_seals) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct shmfd *shmfd; | struct shmfd *shmfd; | ||||
struct file *fp; | struct file *fp; | ||||
char *path; | char *path; | ||||
const char *pr_path; | |||||
void *rl_cookie; | void *rl_cookie; | ||||
size_t pr_pathlen; | |||||
Fnv32_t fnv; | Fnv32_t fnv; | ||||
mode_t cmode; | mode_t cmode; | ||||
int fd, error; | int fd, error; | ||||
#ifdef CAPABILITY_MODE | #ifdef CAPABILITY_MODE | ||||
/* | /* | ||||
* shm_open(2) is only allowed for anonymous objects. | * shm_open(2) is only allowed for anonymous objects. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
if ((flags & O_ACCMODE) == O_RDONLY) { | if ((flags & O_ACCMODE) == O_RDONLY) { | ||||
fdclose(td, fp, fd); | fdclose(td, fp, fd); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
shmfd = shm_alloc(td->td_ucred, cmode); | shmfd = shm_alloc(td->td_ucred, cmode); | ||||
shmfd->shm_seals = initial_seals; | shmfd->shm_seals = initial_seals; | ||||
} else { | } else { | ||||
path = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK); | error = shm_copyin_path(td, userpath, &path); | ||||
pr_path = td->td_ucred->cr_prison->pr_path; | |||||
/* Construct a full pathname for jailed callers. */ | |||||
pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 | |||||
: strlcpy(path, pr_path, MAXPATHLEN); | |||||
error = copyinstr(userpath, path + pr_pathlen, | |||||
MAXPATHLEN - pr_pathlen, NULL); | |||||
#ifdef KTRACE | |||||
if (error == 0 && KTRPOINT(curthread, KTR_NAMEI)) | |||||
ktrnamei(path); | |||||
#endif | |||||
/* Require paths to start with a '/' character. */ | |||||
if (error == 0 && path[pr_pathlen] != '/') | |||||
error = EINVAL; | |||||
if (error) { | if (error) { | ||||
Done Inline Actionserror != 0 kib: error != 0 | |||||
Done Inline ActionsGood catch. Fixed. matthew.bryan_isilon.com: Good catch. Fixed. | |||||
fdclose(td, fp, fd); | fdclose(td, fp, fd); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
free(path, M_SHMFD); | |||||
return (error); | return (error); | ||||
} | } | ||||
AUDIT_ARG_UPATH1_CANON(path); | AUDIT_ARG_UPATH1_CANON(path); | ||||
fnv = fnv_32_str(path, FNV1_32_INIT); | fnv = fnv_32_str(path, FNV1_32_INIT); | ||||
sx_xlock(&shm_dict_lock); | sx_xlock(&shm_dict_lock); | ||||
shmfd = shm_lookup(path, fnv); | shmfd = shm_lookup(path, fnv); | ||||
if (shmfd == NULL) { | if (shmfd == NULL) { | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
NULL, F_SEAL_SEAL)); | NULL, F_SEAL_SEAL)); | ||||
} | } | ||||
#endif | #endif | ||||
int | int | ||||
sys_shm_unlink(struct thread *td, struct shm_unlink_args *uap) | sys_shm_unlink(struct thread *td, struct shm_unlink_args *uap) | ||||
{ | { | ||||
char *path; | char *path; | ||||
const char *pr_path; | |||||
size_t pr_pathlen; | |||||
Fnv32_t fnv; | Fnv32_t fnv; | ||||
int error; | int error; | ||||
path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); | error = shm_copyin_path(td, uap->path, &path); | ||||
pr_path = td->td_ucred->cr_prison->pr_path; | if (error) | ||||
kibUnsubmitted Done Inline Actionserror != 0 kib: error != 0 | |||||
pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 | |||||
: strlcpy(path, pr_path, MAXPATHLEN); | |||||
error = copyinstr(uap->path, path + pr_pathlen, MAXPATHLEN - pr_pathlen, | |||||
NULL); | |||||
if (error) { | |||||
free(path, M_TEMP); | |||||
return (error); | return (error); | ||||
} | |||||
#ifdef KTRACE | |||||
if (KTRPOINT(curthread, KTR_NAMEI)) | |||||
ktrnamei(path); | |||||
#endif | |||||
AUDIT_ARG_UPATH1_CANON(path); | AUDIT_ARG_UPATH1_CANON(path); | ||||
fnv = fnv_32_str(path, FNV1_32_INIT); | fnv = fnv_32_str(path, FNV1_32_INIT); | ||||
sx_xlock(&shm_dict_lock); | sx_xlock(&shm_dict_lock); | ||||
error = shm_remove(path, fnv, td->td_ucred); | error = shm_remove(path, fnv, td->td_ucred); | ||||
sx_xunlock(&shm_dict_lock); | sx_xunlock(&shm_dict_lock); | ||||
free(path, M_TEMP); | free(path, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_shm_rename(struct thread *td, struct shm_rename_args *uap) | sys_shm_rename(struct thread *td, struct shm_rename_args *uap) | ||||
{ | { | ||||
char *path_from = NULL, *path_to = NULL; | char *path_from = NULL, *path_to = NULL; | ||||
Fnv32_t fnv_from, fnv_to; | Fnv32_t fnv_from, fnv_to; | ||||
struct shmfd *fd_from; | struct shmfd *fd_from; | ||||
struct shmfd *fd_to; | struct shmfd *fd_to; | ||||
int error; | int error; | ||||
int flags; | int flags; | ||||
flags = uap->flags; | flags = uap->flags; | ||||
AUDIT_ARG_FFLAGS(flags); | |||||
/* | /* | ||||
* Make sure the user passed only valid flags. | * Make sure the user passed only valid flags. | ||||
* If you add a new flag, please add a new term here. | * If you add a new flag, please add a new term here. | ||||
*/ | */ | ||||
if ((flags & ~( | if ((flags & ~( | ||||
SHM_RENAME_NOREPLACE | | SHM_RENAME_NOREPLACE | | ||||
SHM_RENAME_EXCHANGE | SHM_RENAME_EXCHANGE | ||||
)) != 0) { | )) != 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* EXCHANGE and NOREPLACE don't quite make sense together. Let's | * EXCHANGE and NOREPLACE don't quite make sense together. Let's | ||||
* force the user to choose one or the other. | * force the user to choose one or the other. | ||||
*/ | */ | ||||
if ((flags & SHM_RENAME_NOREPLACE) != 0 && | if ((flags & SHM_RENAME_NOREPLACE) != 0 && | ||||
(flags & SHM_RENAME_EXCHANGE) != 0) { | (flags & SHM_RENAME_EXCHANGE) != 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
#ifdef CAPABILITY_MODE | |||||
/* | /* | ||||
* Malloc zone M_SHMFD, since this path may end up freed later from | * Let's restrict use in capability mode. Let's allow only SHM_ANON uses | ||||
* M_SHMFD if we end up doing an insert. | * in capability mode, to parallel shm_open. Since we have a later check | ||||
* for to == from, and is a no-op, then this becomes simply a bail out. | |||||
*/ | */ | ||||
path_from = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK); | if (IN_CAPABILITY_MODE(td)) { | ||||
kibUnsubmitted Done Inline ActionsI do not see why this chunk is needed. kib: I do not see why this chunk is needed. | |||||
matthew.bryan_isilon.comAuthorUnsubmitted Done Inline ActionsAs I understand it: capability mode generally means that we would disallow messing with any global namespaces. Renaming an shm other than SHM_ANON would be messing with the SHM namespace. So: we quit early with ECAPMODE. I'm sure you know better than I though. So: what is your though more specifically? matthew.bryan_isilon.com: As I understand it: capability mode generally means that we would disallow messing with any… | |||||
kibUnsubmitted Done Inline ActionsI already answered this in my previous reply. The shm_rename(2) syscall is not listed in capabilities.conf, which means that in capability mode it is rejected right away by the infra code without ever entering into the syscall implementation routine. So it is simply impossible to have the test at line 1005 to ever return true. kib: I already answered this in my previous reply. The shm_rename(2) syscall is not listed in… | |||||
matthew.bryan_isilon.comAuthorUnsubmitted Done Inline ActionsWell...I was trying to plan for the future when somebody did add it but neglected to change this file :-p Engineering for quality. But I don't mind removing it. matthew.bryan_isilon.com: Well...I was trying to plan for the future when somebody did add it but neglected to change… | |||||
kevansUnsubmitted Done Inline Actionsshm_rename is also, unfortunately, not suitable for renames involving SHM_ANON mapping as either source or destination anyways, since SHM_ANON is a value that should not be suitable for copyinstr(9). kevans: shm_rename is also, unfortunately, not suitable for renames involving SHM_ANON mapping as… | |||||
matthew.bryan_isilon.comAuthorUnsubmitted Done Inline ActionsYep; SHM_ANON is not allowed at all. There are even tests to make sure of it! matthew.bryan_isilon.com: Yep; SHM_ANON is not allowed at all. There are even tests to make sure of it! | |||||
kibUnsubmitted Not Done Inline ActionsHmm, it is not completely true. If mmap at zero is allowed (it could be), then (char *)1 is a valid pointer. I think we should check for SHM_ANON explicitly before calling copyinstr(9). kib: Hmm, it is not completely true. If mmap at zero is allowed (it could be), then (char *)1 is a… | |||||
matthew.bryan_isilon.comAuthorUnsubmitted Done Inline ActionsGreat point! I never thought of that case. Explicit is better too. I'll check for path in or path out being SHM_ANON. matthew.bryan_isilon.com: Great point! I never thought of that case. Explicit is better too. I'll check for path in or… | |||||
error = copyinstr(uap->path_from, path_from, MAXPATHLEN, NULL); | error = ECAPMODE; | ||||
if (error) | goto out; | ||||
} | |||||
#endif | |||||
error = shm_copyin_path(td, uap->path_from, &path_from); | |||||
if (error != 0) | |||||
goto out; | goto out; | ||||
path_to = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK); | error = shm_copyin_path(td, uap->path_to, &path_to); | ||||
error = copyinstr(uap->path_to, path_to, MAXPATHLEN, NULL); | if (error != 0) | ||||
if (error) | |||||
goto out; | goto out; | ||||
AUDIT_ARG_UPATH1_CANON(path_from); | |||||
AUDIT_ARG_UPATH2_CANON(path_to); | |||||
/* Rename with from/to equal is a no-op */ | /* Rename with from/to equal is a no-op */ | ||||
if (strncmp(path_from, path_to, MAXPATHLEN) == 0) | if (strncmp(path_from, path_to, MAXPATHLEN) == 0) | ||||
Done Inline ActionsI see no point in use of strncmp. kib: I see no point in use of strncmp. | |||||
Done Inline ActionsI think you mean vs strcmp. I just learned that copyinstr makes sure these are null terminated. Thanks. :) matthew.bryan_isilon.com: I think you mean vs strcmp. I just learned that copyinstr makes sure these are null terminated. | |||||
goto out; | goto out; | ||||
fnv_from = fnv_32_str(path_from, FNV1_32_INIT); | fnv_from = fnv_32_str(path_from, FNV1_32_INIT); | ||||
fnv_to = fnv_32_str(path_to, FNV1_32_INIT); | fnv_to = fnv_32_str(path_to, FNV1_32_INIT); | ||||
sx_xlock(&shm_dict_lock); | sx_xlock(&shm_dict_lock); | ||||
fd_from = shm_lookup(path_from, fnv_from); | fd_from = shm_lookup(path_from, fnv_from); | ||||
if (fd_from == NULL) { | if (fd_from == NULL) { | ||||
sx_xunlock(&shm_dict_lock); | |||||
error = ENOENT; | error = ENOENT; | ||||
goto out; | goto out_locked; | ||||
} | } | ||||
fd_to = shm_lookup(path_to, fnv_to); | fd_to = shm_lookup(path_to, fnv_to); | ||||
if ((flags & SHM_RENAME_NOREPLACE) != 0 && fd_to != NULL) { | if ((flags & SHM_RENAME_NOREPLACE) != 0 && fd_to != NULL) { | ||||
sx_xunlock(&shm_dict_lock); | |||||
error = EEXIST; | error = EEXIST; | ||||
goto out; | goto out_locked; | ||||
} | } | ||||
/* | /* | ||||
* Unconditionally prevents shm_remove from invalidating the 'from' | * Unconditionally prevents shm_remove from invalidating the 'from' | ||||
* shm's state. | * shm's state. | ||||
*/ | */ | ||||
shm_hold(fd_from); | shm_hold(fd_from); | ||||
error = shm_remove(path_from, fnv_from, td->td_ucred); | error = shm_remove(path_from, fnv_from, td->td_ucred); | ||||
/* | /* | ||||
* One of my assumptions failed if ENOENT (e.g. locking didn't | * One of my assumptions failed if ENOENT (e.g. locking didn't | ||||
* protect us) | * protect us) | ||||
*/ | */ | ||||
KASSERT(error != ENOENT, ("Our shm disappeared during shm_rename: %s", | KASSERT(error != ENOENT, ("Our shm disappeared during shm_rename: %s", | ||||
path_from)); | path_from)); | ||||
if (error) { | if (error != 0) { | ||||
shm_drop(fd_from); | shm_drop(fd_from); | ||||
sx_xunlock(&shm_dict_lock); | goto out_locked; | ||||
goto out; | |||||
} | } | ||||
/* | /* | ||||
* If we are exchanging, we need to ensure the shm_remove below | * If we are exchanging, we need to ensure the shm_remove below | ||||
* doesn't invalidate the dest shm's state. | * doesn't invalidate the dest shm's state. | ||||
*/ | */ | ||||
if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL) | if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL) | ||||
shm_hold(fd_to); | shm_hold(fd_to); | ||||
/* | /* | ||||
* NOTE: if path_to is not already in the hash, c'est la vie; | * NOTE: if path_to is not already in the hash, c'est la vie; | ||||
* it simply means we have nothing already at path_to to unlink. | * it simply means we have nothing already at path_to to unlink. | ||||
* That is the ENOENT case. | * That is the ENOENT case. | ||||
* | * | ||||
* If we somehow don't have access to unlink this guy, but | * If we somehow don't have access to unlink this guy, but | ||||
* did for the shm at path_from, then relink the shm to path_from | * did for the shm at path_from, then relink the shm to path_from | ||||
* and abort with EACCES. | * and abort with EACCES. | ||||
* | * | ||||
* All other errors: that is weird; let's relink and abort the | * All other errors: that is weird; let's relink and abort the | ||||
* operation. | * operation. | ||||
*/ | */ | ||||
error = shm_remove(path_to, fnv_to, td->td_ucred); | error = shm_remove(path_to, fnv_to, td->td_ucred); | ||||
if (error && error != ENOENT) { | if (error != 0 && error != ENOENT) { | ||||
shm_insert(path_from, fnv_from, fd_from); | shm_insert(path_from, fnv_from, fd_from); | ||||
shm_drop(fd_from); | shm_drop(fd_from); | ||||
/* Don't free path_from now, since the hash references it */ | /* Don't free path_from now, since the hash references it */ | ||||
path_from = NULL; | path_from = NULL; | ||||
sx_xunlock(&shm_dict_lock); | goto out_locked; | ||||
goto out; | |||||
} | } | ||||
shm_insert(path_to, fnv_to, fd_from); | shm_insert(path_to, fnv_to, fd_from); | ||||
/* Don't free path_to now, since the hash references it */ | /* Don't free path_to now, since the hash references it */ | ||||
path_to = NULL; | path_to = NULL; | ||||
/* We kept a ref when we removed, and incremented again in insert */ | /* We kept a ref when we removed, and incremented again in insert */ | ||||
shm_drop(fd_from); | shm_drop(fd_from); | ||||
#ifdef DEBUG | |||||
KASSERT(fd_from->shm_refs > 0, ("Expected >0 refs; got: %d\n", | KASSERT(fd_from->shm_refs > 0, ("Expected >0 refs; got: %d\n", | ||||
fd_from->shm_refs)); | fd_from->shm_refs)); | ||||
#endif | |||||
if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL) { | if ((flags & SHM_RENAME_EXCHANGE) != 0 && fd_to != NULL) { | ||||
shm_insert(path_from, fnv_from, fd_to); | shm_insert(path_from, fnv_from, fd_to); | ||||
path_from = NULL; | path_from = NULL; | ||||
shm_drop(fd_to); | shm_drop(fd_to); | ||||
#ifdef DEBUG | |||||
KASSERT(fd_to->shm_refs > 0, ("Expected >0 refs; got: %d\n", | KASSERT(fd_to->shm_refs > 0, ("Expected >0 refs; got: %d\n", | ||||
fd_to->shm_refs)); | fd_to->shm_refs)); | ||||
#endif | |||||
} | } | ||||
error = 0; | error = 0; | ||||
out_locked: | |||||
Done Inline ActionsNo point in the assingment. kib: No point in the assingment. | |||||
Done Inline ActionsIt is needed for the ENOENT case above. matthew.bryan_isilon.com: It is needed for the ENOENT case above. | |||||
Not Done Inline ActionsYou mean, around line 1067. I suggest to reset error at that location, then. kib: You mean, around line 1067. I suggest to reset error at that location, then. | |||||
Done Inline ActionsGreat idea. Done. matthew.bryan_isilon.com: Great idea. Done. | |||||
sx_xunlock(&shm_dict_lock); | sx_xunlock(&shm_dict_lock); | ||||
Done Inline ActionsExtra blank line. kib: Extra blank line. | |||||
out: | out: | ||||
if (path_from != NULL) | if (path_from != NULL) | ||||
Done Inline ActionsNo need to check for NULL (I think I already noted that). kib: No need to check for NULL (I think I already noted that). | |||||
free(path_from, M_SHMFD); | free(path_from, M_SHMFD); | ||||
if (path_to != NULL) | if (path_to != NULL) | ||||
Done Inline ActionsSame. kib: Same. | |||||
free(path_to, M_SHMFD); | free(path_to, M_SHMFD); | ||||
return(error); | return (error); | ||||
} | } | ||||
int | int | ||||
shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize, | shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize, | ||||
vm_prot_t prot, vm_prot_t cap_maxprot, int flags, | vm_prot_t prot, vm_prot_t cap_maxprot, int flags, | ||||
vm_ooffset_t foff, struct thread *td) | vm_ooffset_t foff, struct thread *td) | ||||
{ | { | ||||
struct shmfd *shmfd; | struct shmfd *shmfd; | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |
No point in the assignment.