extractedLnx/linux-2.4.19/fs/intermezzo/psdev.c_presto_psdev_ioctl.c
static int presto_psdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct upc_comm *upccom;
/* XXX is this rdev or dev? */
kdev_t dev = inode->i_rdev;
ENTRY;
upccom = presto_psdev_f2u(file);
if ( !upccom) {
printk("InterMezzo: %s, bad device %s\n",
__FUNCTION__, kdevname(dev));
EXIT;
return -ENODEV;
}
switch(cmd) {
case TCGETS:
return -EINVAL;
case PRESTO_GETMOUNT: {
/* return all the mounts for this device. */
int minor = 0;
int len, outlen;
struct readmount readmount;
struct readmount *user_readmount = (struct readmount *) arg;
char * tmp;
int error = 0;
if (copy_from_user(&readmount, (void *)arg, sizeof(readmount)))
{
EXIT;
return -EFAULT;
}
len = readmount.io_len;
minor = MINOR(dev);
PRESTO_ALLOC(tmp, char *, len);
if (!tmp) {
EXIT;
return -ENOMEM;
}
outlen = presto_sprint_mounts(tmp, len, minor);
CDEBUG(D_PSDEV, "presto_sprint_mounts returns %d bytes\n",
outlen);
/* as this came out on 1/3/2000, it could NEVER work.
* So fix it ... RGM
* I mean, let's let the compiler do a little work ...
* gcc suggested the extra ()
*/
if (copy_to_user(readmount.io_string, tmp, outlen)) {
CDEBUG(D_PSDEV, "Copy_to_user string 0x%p failed\n",
readmount.io_string);
error = -EFAULT;
}
if (!error && copy_to_user(&(user_readmount->io_len),
&outlen, sizeof(int))) {
CDEBUG(D_PSDEV, "Copy_to_user len @0x%p failed\n",
&(user_readmount->io_len));
error = -EFAULT;
}
PRESTO_FREE(tmp, len);
EXIT;
return error;
}
case PRESTO_SETPID: {
/*
* This ioctl is performed by each Lento that starts up
* and wants to do further communication with presto.
*/
CDEBUG(D_PSDEV, "Setting current pid to %d\n", current->pid);
upccom->uc_pid = current->pid;
if ( !list_empty(&upccom->uc_processing) ) {
struct list_head *lh;
struct upc_req *req;
printk("WARNING: setpid & processing not empty!\n");
lh = &upccom->uc_processing;
while ( (lh = lh->next) != &upccom->uc_processing) {
req = list_entry(lh, struct upc_req, rq_chain);
/* freeing of req and data is done by the sleeper */
wake_up(&req->rq_sleep);
}
}
if ( !list_empty(&upccom->uc_processing) ) {
printk("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
}
EXIT;
return 0;
}
case PRESTO_CLEAR_FSETROOT: {
/*
* Close KML files.
*/
int error;
int saved_pid = upccom->uc_pid;
char *path;
struct {
char *path;
unsigned int path_len;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX)
{
EXIT;
return -EINVAL;
}
PRESTO_ALLOC(path, char *, input.path_len + 1);
if ( !path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(path, input.path, input.path_len)) {
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return -EFAULT;
}
path[input.path_len] = '\0';
CDEBUG(D_PSDEV, "clear_fsetroot: path %s\n", path);
upccom->uc_pid = current->pid;
error = presto_clear_fsetroot(path);
upccom->uc_pid = saved_pid;
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return error;
}
case PRESTO_CLEAR_ALL_FSETROOTS: {
/*
* Close KML files.
*/
int error;
int saved_pid = upccom->uc_pid;
char *path;
struct {
char *path;
unsigned int path_len;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
PRESTO_ALLOC(path, char *, input.path_len + 1);
if ( !path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(path, input.path, input.path_len)) {
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return -EFAULT;
}
path[input.path_len] = '\0';
CDEBUG(D_PSDEV, "clear_all_fsetroot: path %s\n", path);
upccom->uc_pid = current->pid;
error = presto_clear_all_fsetroots(path);
upccom->uc_pid = saved_pid;
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return error;
}
case PRESTO_GET_KMLSIZE: {
int error;
int saved_pid = upccom->uc_pid;
char *path;
size_t size = 0;
struct {
__u64 size;
char *path;
unsigned int path_len;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
PRESTO_ALLOC(path, char *, input.path_len + 1);
if ( !path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(path, input.path, input.path_len)) {
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return -EFAULT;
}
path[input.path_len] = '\0';
CDEBUG(D_PSDEV, "get_kmlsize: len %d path %s\n",
input.path_len, path);
upccom->uc_pid = current->pid;
error = presto_get_kmlsize(path, &size);
PRESTO_FREE(path, input.path_len + 1);
if (error) {
EXIT;
return error;
}
input.size = size;
upccom->uc_pid = saved_pid;
CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size);
EXIT;
if (copy_to_user((char *)arg, &input, sizeof(input)))
return -EFAULT;
return 0;
}
case PRESTO_GET_RECNO: {
int error;
int saved_pid = upccom->uc_pid;
char *path;
off_t recno = 0;
struct {
__u64 recno;
char *path;
unsigned int path_len;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
PRESTO_ALLOC(path, char *, input.path_len + 1);
if ( !path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(path, input.path, input.path_len)) {
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return -EFAULT;
}
path[input.path_len] = '\0';
CDEBUG(D_PSDEV, "get_recno: len %d path %s\n",
input.path_len, path);
upccom->uc_pid = current->pid;
error = presto_get_lastrecno(path, &recno);
PRESTO_FREE(path, input.path_len + 1);
if (error) {
EXIT;
return error;
}
input.recno = recno;
upccom->uc_pid = saved_pid;
CDEBUG(D_PSDEV, "get_recno: recno = %d\n", (int) recno);
EXIT;
if (copy_to_user((char *)arg, &input, sizeof(input)))
return -EFAULT;
return 0;
}
case PRESTO_SET_FSETROOT: {
/*
* Save information about the cache, and initialize "special"
* cache files (KML, etc).
*/
int error;
int saved_pid = upccom->uc_pid;
char *fsetname;
char *path;
struct {
char *path;
unsigned int path_len;
char *name;
unsigned int name_len;
int id;
int flags;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.name_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
PRESTO_ALLOC(path, char *, input.path_len + 1);
if ( !path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(path, input.path, input.path_len)) {
EXIT;
error = -EFAULT;
goto exit_free_path;
}
path[input.path_len] = '\0';
PRESTO_ALLOC(fsetname, char *, input.name_len + 1);
if ( !fsetname ) {
error = -ENOMEM;
EXIT;
goto exit_free_path;
}
if (copy_from_user(fsetname, input.name, input.name_len)) {
EXIT;
error = -EFAULT;
goto exit_free_fsetname;
}
fsetname[input.name_len] = '\0';
CDEBUG(D_PSDEV,
"set_fsetroot: path %s name %s, id %d, flags %x\n",
path, fsetname, input.id, input.flags);
upccom->uc_pid = current->pid;
error = presto_set_fsetroot(path, fsetname, input.id,input.flags);
upccom->uc_pid = saved_pid;
if ( error ) {
EXIT;
goto exit_free_fsetname;
}
/* fsetname is kept in the fset, so don't free it now */
PRESTO_FREE(path, input.path_len + 1);
EXIT;
return 0;
exit_free_fsetname:
PRESTO_FREE(fsetname, input.name_len + 1);
exit_free_path:
PRESTO_FREE(path, input.path_len + 1);
return error;
}
case PRESTO_CLOSE_JOURNALF: {
int saved_pid = upccom->uc_pid;
int error;
CDEBUG(D_SUPER, "HELLO\n");
/* pretend we are lento: we should lock something */
upccom->uc_pid = current->pid;
error = presto_close_journal_file(NULL);
CDEBUG(D_PSDEV, "error is %d\n", error);
upccom->uc_pid = saved_pid;
EXIT;
return error;
}
case PRESTO_GETOPT:
case PRESTO_SETOPT: {
/* return all the mounts for this device. */
int dosetopt(int, struct psdev_opt *);
int dogetopt(int, struct psdev_opt *);
int minor = 0;
struct psdev_opt kopt;
int error = 0;
struct psdev_opt *user_opt = (struct psdev_opt *) arg;
if (copy_from_user(&kopt, (void *)arg, sizeof(kopt))) {
printk("psdev: can't copyin %Zd bytes from %p to %p\n",
sizeof(kopt), (struct kopt *) arg, &kopt);
EXIT;
return -EFAULT;
}
minor = MINOR(dev);
if (cmd == PRESTO_SETOPT)
error = dosetopt(minor, &kopt);
if ( error ) {
CDEBUG(D_PSDEV,
"dosetopt failed minor %d, opt %d, val %d\n",
minor, kopt.optname, kopt.optval);
EXIT;
return error;
}
error = dogetopt(minor, &kopt);
if ( error ) {
CDEBUG(D_PSDEV,
"dogetopt failed minor %d, opt %d, val %d\n",
minor, kopt.optname, kopt.optval);
EXIT;
return error;
}
if (copy_to_user(user_opt, &kopt, sizeof(kopt))) {
CDEBUG(D_PSDEV, "Copy_to_user opt 0x%p failed\n",
user_opt);
EXIT;
return -EFAULT;
}
CDEBUG(D_PSDEV, "dosetopt minor %d, opt %d, val %d return %d\n",
minor, kopt.optname, kopt.optval, error);
EXIT;
return 0;
}
case PRESTO_VFS_SETATTR: {
int error;
struct lento_input_attr input;
struct iattr iattr;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
iattr.ia_valid = input.valid;
iattr.ia_mode = (umode_t)input.mode;
iattr.ia_uid = (uid_t)input.uid;
iattr.ia_gid = (gid_t)input.gid;
iattr.ia_size = (off_t)input.size;
iattr.ia_atime = (time_t)input.atime;
iattr.ia_mtime = (time_t)input.mtime;
iattr.ia_ctime = (time_t)input.ctime;
iattr.ia_attr_flags = input.attr_flags;
error = lento_setattr(input.name, &iattr, &input.info);
EXIT;
return error;
}
case PRESTO_VFS_CREATE: {
int error;
struct lento_input_mode input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_create(input.name, input.mode, &input.info);
EXIT;
return error;
}
case PRESTO_VFS_LINK: {
int error;
struct lento_input_old_new input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_link(input.oldname, input.newname, &input.info);
EXIT;
return error;
}
case PRESTO_VFS_UNLINK: {
int error;
struct lento_input input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_unlink(input.name, &input.info);
EXIT;
return error;
}
case PRESTO_VFS_SYMLINK: {
int error;
struct lento_input_old_new input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_symlink(input.oldname, input.newname,&input.info);
EXIT;
return error;
}
case PRESTO_VFS_MKDIR: {
int error;
struct lento_input_mode input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_mkdir(input.name, input.mode, &input.info);
EXIT;
return error;
}
case PRESTO_VFS_RMDIR: {
int error;
struct lento_input input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_rmdir(input.name, &input.info);
EXIT;
return error;
}
case PRESTO_VFS_MKNOD: {
int error;
struct lento_input_dev input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_mknod(input.name, input.mode,
MKDEV(input.major,input.minor),&input.info);
EXIT;
return error;
}
case PRESTO_VFS_RENAME: {
int error;
struct lento_input_old_new input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
error = lento_rename(input.oldname, input.newname, &input.info);
EXIT;
return error;
}
#ifdef CONFIG_FS_EXT_ATTR
/* IOCTL to create/modify an extended attribute */
case PRESTO_VFS_SETEXTATTR: {
int error;
struct lento_input_ext_attr input;
char *name;
char *buffer;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
/* Now setup the input parameters */
PRESTO_ALLOC(name, char *, input.name_len+1);
/* We need null terminated strings for attr names */
name[input.name_len] = '\0';
if (copy_from_user(name, input.name, input.name_len)) {
EXIT;
PRESTO_FREE(name,input.name_len+1);
return -EFAULT;
}
PRESTO_ALLOC(buffer, char *, input.buffer_len+1);
if (copy_from_user(buffer, input.buffer, input.buffer_len)) {
EXIT;
PRESTO_FREE(name,input.name_len+1);
PRESTO_FREE(buffer,input.buffer_len+1);
return -EFAULT;
}
/* Make null terminated for easy printing */
buffer[input.buffer_len]='\0';
CDEBUG(D_PSDEV," setextattr params: name %s, valuelen %d,"
" value %s, attr flags %x, mode %o, slot offset %d,"
" recno %d, kml offset %lu, flags %x, time %d\n",
name, input.buffer_len, buffer, input.flags, input.mode,
input.info.slot_offset, input.info.recno,
(unsigned long) input.info.kml_offset, input.info.flags,
input.info.updated_time);
error=lento_set_ext_attr
(input.path,name,buffer,input.buffer_len,
input.flags, input.mode, &input.info);
PRESTO_FREE(name,input.name_len+1);
PRESTO_FREE(buffer,input.buffer_len+1);
EXIT;
return error;
}
/* IOCTL to delete an extended attribute */
case PRESTO_VFS_DELEXTATTR: {
int error;
struct lento_input_ext_attr input;
char *name;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
/* Now setup the input parameters */
PRESTO_ALLOC(name, char *, input.name_len+1);
/* We need null terminated strings for attr names */
name[input.name_len] = '\0';
if (copy_from_user(name, input.name, input.name_len)) {
EXIT;
PRESTO_FREE(name,input.name_len+1);
return -EFAULT;
}
CDEBUG(D_PSDEV," delextattr params: name %s,"
" attr flags %x, mode %o, slot offset %d, recno %d,"
" kml offset %lu, flags %x, time %d\n",
name, input.flags, input.mode,
input.info.slot_offset, input.info.recno,
(unsigned long) input.info.kml_offset, input.info.flags,
input.info.updated_time);
error=lento_set_ext_attr
(input.path,name,NULL,0,input.flags,
input.mode,&input.info);
PRESTO_FREE(name,input.name_len+1);
EXIT;
return error;
}
#endif
case PRESTO_VFS_IOPEN: {
struct lento_input_iopen input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
input.fd = lento_iopen(input.name, (ino_t)input.ino,
input.generation, input.flags);
CDEBUG(D_PIOCTL, "lento_iopen file descriptor: %d\n", input.fd);
if (input.fd < 0) {
EXIT;
return input.fd;
}
EXIT;
if (copy_to_user((char *)arg, &input, sizeof(input)))
return -EFAULT;
return 0;
}
case PRESTO_VFS_CLOSE: {
int error;
struct lento_input_close input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
CDEBUG(D_PIOCTL, "lento_close file descriptor: %d\n", input.fd);
error = lento_close(input.fd, &input.info);
EXIT;
return error;
}
case PRESTO_BACKFETCH_LML: {
char *user_path;
struct lml_arg {
char *path;
__u32 path_len;
__u64 remote_ino;
__u32 remote_generation;
__u32 remote_version;
struct presto_version remote_file_version;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
user_path = input.path;
PRESTO_ALLOC(input.path, char *, input.path_len + 1);
if ( !input.path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(input.path, user_path, input.path_len)) {
EXIT;
PRESTO_FREE(input.path, input.path_len + 1);
return -EFAULT;
}
input.path[input.path_len] = '\0';
CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
return lento_write_lml(input.path,
input.remote_ino,
input.remote_generation,
input.remote_version,
&input.remote_file_version);
}
case PRESTO_CANCEL_LML: {
char *user_path;
struct lml_arg {
char *path;
__u64 lml_offset;
__u32 path_len;
__u64 remote_ino;
__u32 remote_generation;
__u32 remote_version;
struct lento_vfs_context info;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
user_path = input.path;
PRESTO_ALLOC(input.path, char *, input.path_len + 1);
if ( !input.path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(input.path, user_path, input.path_len)) {
EXIT;
PRESTO_FREE(input.path, input.path_len + 1);
return -EFAULT;
}
input.path[input.path_len] = '\0';
CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
return lento_cancel_lml(input.path,
input.lml_offset,
input.remote_ino,
input.remote_generation,
input.remote_version,
&input.info);
}
case PRESTO_COMPLETE_CLOSES: {
char *user_path;
int error;
struct lml_arg {
char *path;
__u32 path_len;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
user_path = input.path;
PRESTO_ALLOC(input.path, char *, input.path_len + 1);
if ( !input.path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(input.path, user_path, input.path_len)) {
EXIT;
PRESTO_FREE(input.path, input.path_len + 1);
return -EFAULT;
}
input.path[input.path_len] = '\0';
CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
error = lento_complete_closes(input.path);
PRESTO_FREE(input.path, input.path_len + 1);
return error;
}
case PRESTO_RESET_FSET: {
char *user_path;
struct lml_arg {
char *path;
__u32 path_len;
__u64 offset;
__u32 recno;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
user_path = input.path;
PRESTO_ALLOC(input.path, char *, input.path_len + 1);
if ( !input.path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(input.path, user_path, input.path_len)) {
EXIT;
PRESTO_FREE(input.path, input.path_len + 1);
return -EFAULT;
}
input.path[input.path_len] = '\0';
CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
return lento_reset_fset(input.path, input.offset, input.recno);
}
case PRESTO_MARK: {
char *user_path;
int res = 0; /* resulting flags - returned to user */
int error;
struct {
int mark_what;
int and_flag;
int or_flag;
unsigned int path_len;
char *path;
} input;
if (copy_from_user(&input, (char *)arg, sizeof(input))) {
EXIT;
return -EFAULT;
}
if(input.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
user_path = input.path;
PRESTO_ALLOC(input.path, char *, input.path_len + 1);
if ( !input.path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(input.path, user_path, input.path_len)) {
EXIT;
PRESTO_FREE(input.path, input.path_len + 1);
return -EFAULT;
}
input.path[input.path_len] = '\0';
CDEBUG(D_DOWNCALL, "mark name: %s, and: %x, or: %x, what %d\n",
input.path, input.and_flag, input.or_flag,
input.mark_what);
switch (input.mark_what) {
case MARK_DENTRY:
error = presto_mark_dentry(input.path,
input.and_flag,
input.or_flag, &res);
break;
case MARK_FSET:
error = presto_mark_fset(input.path,
input.and_flag,
input.or_flag, &res);
break;
case MARK_CACHE:
error = presto_mark_cache(input.path,
input.and_flag,
input.or_flag, &res);
break;
case MARK_GETFL: {
int fflags, cflags;
input.and_flag = 0xffffffff;
input.or_flag = 0;
error = presto_mark_dentry(input.path,
input.and_flag,
input.or_flag, &res);
if (error)
break;
error = presto_mark_fset(input.path,
input.and_flag,
input.or_flag, &fflags);
if (error)
break;
error = presto_mark_cache(input.path,
input.and_flag,
input.or_flag, &cflags);
if (error)
break;
input.and_flag = fflags;
input.or_flag = cflags;
break;
}
default:
error = -EINVAL;
}
PRESTO_FREE(input.path, input.path_len + 1);
if (error == -EBUSY) {
input.and_flag = error;
error = 0;
}
if (error) {
EXIT;
return error;
}
/* return the correct cookie to wait for */
input.mark_what = res;
if (copy_to_user((char *)arg, &input, sizeof(input)))
return -EFAULT;
return 0;
}
#ifdef CONFIG_KREINT
case PRESTO_REINT_BEGIN:
return begin_kml_reint (file, arg);
case PRESTO_DO_REINT:
return do_kml_reint (file, arg);
case PRESTO_REINT_END:
return end_kml_reint (file, arg);
#endif
case PRESTO_RELEASE_PERMIT: {
int error;
char *user_path;
struct {
int cookie;
unsigned int path_len;
char *path;
} permit;
if (copy_from_user(&permit, (char *)arg, sizeof(permit))) {
EXIT;
return -EFAULT;
}
if(permit.path_len > PATH_MAX) {
EXIT;
return -EINVAL;
}
user_path = permit.path;
PRESTO_ALLOC(permit.path, char *, permit.path_len + 1);
if ( !permit.path ) {
EXIT;
return -ENOMEM;
}
if (copy_from_user(permit.path, user_path, permit.path_len)) {
EXIT;
PRESTO_FREE(permit.path, permit.path_len + 1);
return -EFAULT;
}
permit.path[permit.path_len] = '\0';
CDEBUG(D_DOWNCALL, "release permit: %s, in cookie=%d\n",
permit.path, permit.cookie);
error = presto_permit_downcall(permit.path, &permit.cookie);
PRESTO_FREE(permit.path, permit.path_len + 1);
if (error) {
EXIT;
return error;
}
/* return the correct cookie to wait for */
if (copy_to_user((char *)arg, &permit, sizeof(permit)))
return -EFAULT;
return 0;
}
default:
CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd);
CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n",
PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
EXIT;
}
return -EINVAL;
}
Generated by GNU enscript 1.6.4.