/* O_NOATIME can only be set by the owner or superuser */ if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME)) if (!inode_owner_or_capable(file_mnt_idmap(filp), inode)) return -EPERM;
/* required for strict SunOS emulation */ if (O_NONBLOCK != O_NDELAY) if (arg & O_NDELAY)
arg |= O_NONBLOCK;
/* Pipe packetized mode is controlled by O_DIRECT flag */ if (!S_ISFIFO(inode->i_mode) &&
(arg & O_DIRECT) &&
!(filp->f_mode & FMODE_CAN_ODIRECT)) return -EINVAL;
if (filp->f_op->check_flags)
error = filp->f_op->check_flags(arg); if (error) return error;
switch (hint) { case RWH_WRITE_LIFE_NOT_SET: case RWH_WRITE_LIFE_NONE: case RWH_WRITE_LIFE_SHORT: case RWH_WRITE_LIFE_MEDIUM: case RWH_WRITE_LIFE_LONG: case RWH_WRITE_LIFE_EXTREME: returntrue; default: returnfalse;
}
}
/* Let the caller figure out whether a given file was just created. */ staticlong f_created_query(conststruct file *filp)
{ return !!(filp->f_mode & FMODE_CREATED);
}
staticint f_owner_sig(struct file *filp, int signum, bool setsig)
{ int ret = 0; struct fown_struct *f_owner;
might_sleep();
if (setsig) { if (!valid_signal(signum)) return -EINVAL;
ret = file_f_owner_allocate(filp); if (ret) return ret;
}
f_owner = file_f_owner(filp); if (setsig)
f_owner->signum = signum; elseif (f_owner)
ret = f_owner->signum; return ret;
}
staticlong do_fcntl(int fd, unsignedint cmd, unsignedlong arg, struct file *filp)
{ void __user *argp = (void __user *)arg; int argi = (int)arg; struct flock flock; long err = -EINVAL;
switch (cmd) { case F_CREATED_QUERY:
err = f_created_query(filp); break; case F_DUPFD:
err = f_dupfd(argi, filp, 0); break; case F_DUPFD_CLOEXEC:
err = f_dupfd(argi, filp, O_CLOEXEC); break; case F_DUPFD_QUERY:
err = f_dupfd_query(argi, filp); break; case F_GETFD:
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; break; case F_SETFD:
err = 0;
set_close_on_exec(fd, argi & FD_CLOEXEC); break; case F_GETFL:
err = filp->f_flags; break; case F_SETFL:
err = setfl(fd, filp, argi); break; #if BITS_PER_LONG != 32 /* 32-bit arches must use fcntl64() */ case F_OFD_GETLK: #endif case F_GETLK: if (copy_from_user(&flock, argp, sizeof(flock))) return -EFAULT;
err = fcntl_getlk(filp, cmd, &flock); if (!err && copy_to_user(argp, &flock, sizeof(flock))) return -EFAULT; break; #if BITS_PER_LONG != 32 /* 32-bit arches must use fcntl64() */ case F_OFD_SETLK: case F_OFD_SETLKW:
fallthrough; #endif case F_SETLK: case F_SETLKW: if (copy_from_user(&flock, argp, sizeof(flock))) return -EFAULT;
err = fcntl_setlk(fd, filp, cmd, &flock); break; case F_GETOWN: /* *XXXIff_ownerisaprocessgroup,the *negativereturnvaluewillgetconverted *intoanerror.Oops.Ifwekeepthe *currentsyscallconventions,theonlyway *tofixthiswillbeinlibc.
*/
err = f_getown(filp);
force_successful_syscall_return(); break; case F_SETOWN:
err = f_setown(filp, argi, 1); break; case F_GETOWN_EX:
err = f_getown_ex(filp, arg); break; case F_SETOWN_EX:
err = f_setown_ex(filp, arg); break; case F_GETOWNER_UIDS:
err = f_getowner_uids(filp, arg); break; case F_GETSIG:
err = f_owner_sig(filp, 0, false); break; case F_SETSIG:
err = f_owner_sig(filp, argi, true); break; case F_GETLEASE:
err = fcntl_getlease(filp); break; case F_SETLEASE:
err = fcntl_setlease(fd, filp, argi); break; case F_NOTIFY:
err = fcntl_dirnotify(fd, filp, argi); break; case F_SETPIPE_SZ: case F_GETPIPE_SZ:
err = pipe_fcntl(filp, cmd, argi); break; case F_ADD_SEALS: case F_GET_SEALS:
err = memfd_fcntl(filp, cmd, argi); break; case F_GET_RW_HINT:
err = fcntl_get_rw_hint(filp, cmd, arg); break; case F_SET_RW_HINT:
err = fcntl_set_rw_hint(filp, cmd, arg); break; default: break;
} return err;
}
staticint check_fcntl_cmd(unsigned cmd)
{ switch (cmd) { case F_CREATED_QUERY: case F_DUPFD: case F_DUPFD_CLOEXEC: case F_DUPFD_QUERY: case F_GETFD: case F_SETFD: case F_GETFL: return1;
} return0;
}
staticvoid send_sigio_to_task(struct task_struct *p, struct fown_struct *fown, int fd, int reason, enum pid_type type)
{ /* *F_SETSIGcanchange->signumlocklessinparallel,make *surewereaditonceandusethesamevaluethroughout.
*/ int signum = READ_ONCE(fown->signum);
if (!sigio_perm(p, fown, signum)) return;
switch (signum) { default: {
kernel_siginfo_t si;
/* Queue a rt signal with the appropriate fd as its value.WeuseSI_SIGIOasthesource,not SI_KERNEL,sincekernelsignalsalwaysget deliveredevenifwecan'tqueue.Failureto queueinthiscase_should_bereported;wefall
back to SIGIO in that case. --sct */
clear_siginfo(&si);
si.si_signo = signum;
si.si_errno = 0;
si.si_code = reason; /* *PosixdefiniesPOLL_INandfriendstobesignal *specificsi_codesforSIG_POLL.Linuxextended *thesesi_codestoothersignalsinawaythatis *ambiguousifothersignalsalsohavesignal *specificsi_codes.InthatcaseuseSI_SIGIOinstead *toremovetheambiguity.
*/ if ((signum != SIGPOLL) && sig_specific_sicodes(signum))
si.si_code = SI_SIGIO;
/* Make sure we are called with one of the POLL_* reasons,otherwisewecouldleakkernelstackinto
userspace. */
BUG_ON((reason < POLL_IN) || ((reason - POLL_IN) >= NSIGPOLL)); if (reason - POLL_IN >= NSIGPOLL)
si.si_band = ~0L; else
si.si_band = mangle_poll(band_table[reason - POLL_IN]);
si.si_fd = fd; if (!do_send_sig_info(signum, &si, p, type)) break;
}
fallthrough; /* fall back on the old plain SIGIO signal */ case0:
do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, type);
}
}
void send_sigio(struct fown_struct *fown, int fd, int band)
{ struct task_struct *p; enum pid_type type; unsignedlong flags; struct pid *pid;
read_lock_irqsave(&fown->lock, flags);
type = fown->pid_type;
pid = fown->pid; if (!pid) goto out_unlock_fown;
/* *fasync_helper()isusedbyalmostallcharacterdevicedrivers *tosetupthefasyncqueue,andforregularfilesbythefile *leasecode.Itreturnsnegativeonerror,0ifitdidnochanges *andpositiveifitadded/deletedtheentry.
*/ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{ if (!on) return fasync_remove_entry(filp, fapp); return fasync_add_entry(fd, filp, fapp);
}
EXPORT_SYMBOL(fasync_helper);
/* *rcu_read_lock()isheld
*/ staticvoid kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
{ while (fa) { struct fown_struct *fown; unsignedlong flags;
if (fa->magic != FASYNC_MAGIC) {
printk(KERN_ERR "kill_fasync: bad magic number in " "fasync_struct!\n"); return;
}
read_lock_irqsave(&fa->fa_lock, flags); if (fa->fa_file) {
fown = file_f_owner(fa->fa_file); if (!fown) goto next; /* Don't send SIGURG to processes which have not set a queuedsignum:SIGURGhasitsowndefaultsignalling
mechanism. */ if (!(sig == SIGURG && fown->signum == 0))
send_sigio(fown, fa->fa_fd, band);
}
next:
read_unlock_irqrestore(&fa->fa_lock, flags);
fa = rcu_dereference(fa->fa_next);
}
}
void kill_fasync(struct fasync_struct **fp, int sig, int band)
{ /* First a quick test without locking: usually *thelistisempty.
*/ if (*fp) {
rcu_read_lock();
kill_fasync_rcu(rcu_dereference(*fp), sig, band);
rcu_read_unlock();
}
}
EXPORT_SYMBOL(kill_fasync);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.