static int __snd_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); struct snd_minor *mptr = NULL; const struct file_operations *old_fops; int err = 0; if (minor >= ARRAY_SIZE(snd_minors)) return -ENODEV; mptr = snd_minors[minor]; if (mptr == NULL) { #ifdef CONFIG_MODULES int dev = SNDRV_MINOR_DEVICE(minor); if (dev == SNDRV_MINOR_CONTROL) { /* /dev/aloadC? */ int card = SNDRV_MINOR_CARD(minor); if (snd_cards[card] == NULL) snd_request_card(card); } else if (dev == SNDRV_MINOR_GLOBAL) { /* /dev/aloadSEQ */ snd_request_other(minor); } #ifndef CONFIG_SND_DYNAMIC_MINORS /* /dev/snd/{controlC?,seq} */ mptr = snd_minors[minor]; if (mptr == NULL) #endif #endif return -ENODEV; } old_fops = file->f_op; file->f_op = fops_get(mptr->f_ops); if (file->f_op == NULL) { file->f_op = old_fops; return -ENODEV; } if (file->f_op->open) err = file->f_op->open(inode, file); if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } fops_put(old_fops); return err; }
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file *f = // get an empty file structure f->f_flags = flags; // call open() used inode struct inode = dentry->d_inode; f->f_op = fops_get(inode->i_fop); f->f_op = open(inode, f); }
static int phone_open(struct inode *inode, struct file *file) { unsigned int minor = MINOR(inode->i_rdev); int err = 0; struct phone_device *p; struct file_operations *old_fops, *new_fops = NULL; if (minor >= PHONE_NUM_DEVICES) return -ENODEV; down(&phone_lock); p = phone_device[minor]; if (p) new_fops = fops_get(p->f_op); if (!new_fops) { char modname[32]; up(&phone_lock); sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor); request_module(modname); down(&phone_lock); p = phone_device[minor]; if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL) { err=-ENODEV; goto end; } } old_fops = file->f_op; file->f_op = new_fops; if (p->open) err = p->open(p, file); /* Tell the device it is open */ if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } fops_put(old_fops); end: up(&phone_lock); return err; }
static int phone_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); int err = 0; struct phone_device *p; const struct file_operations *old_fops, *new_fops = NULL; if (minor >= PHONE_NUM_DEVICES) return -ENODEV; lock_kernel(); mutex_lock(&phone_lock); p = phone_device[minor]; if (p) new_fops = fops_get(p->f_op); if (!new_fops) { mutex_unlock(&phone_lock); request_module("char-major-%d-%d", PHONE_MAJOR, minor); mutex_lock(&phone_lock); p = phone_device[minor]; if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL) { err=-ENODEV; goto end; } } old_fops = file->f_op; file->f_op = new_fops; if (p->open) err = p->open(p, file); /* Tell the device it is open */ if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } fops_put(old_fops); end: mutex_unlock(&phone_lock); unlock_kernel(); return err; }
static int snd_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); struct snd_minor *mptr = NULL; const struct file_operations *old_fops; int err = 0; if (minor >= ARRAY_SIZE(snd_minors)) return -ENODEV; mutex_lock(&sound_mutex); mptr = snd_minors[minor]; if (mptr == NULL) { mptr = autoload_device(minor); if (!mptr) { mutex_unlock(&sound_mutex); return -ENODEV; } } old_fops = file->f_op; file->f_op = fops_get(mptr->f_ops); if (file->f_op == NULL) { file->f_op = old_fops; err = -ENODEV; } mutex_unlock(&sound_mutex); if (err < 0) return err; if (file->f_op->open) { err = file->f_op->open(inode, file); if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } } fops_put(old_fops); return err; }
static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; mutex_lock(&dvbdev_mutex); down_read(&minor_rwsem); dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; const struct file_operations *old_fops; file->private_data = dvbdev; old_fops = file->f_op; file->f_op = fops_get(dvbdev->fops); if (file->f_op == NULL) { file->f_op = old_fops; goto fail; } if(file->f_op->open) { mutex_unlock(&dvbdev_mutex); err = file->f_op->open(inode,file); mutex_lock(&dvbdev_mutex); } if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } fops_put(old_fops); up_read(&minor_rwsem); mutex_unlock(&dvbdev_mutex); return err; } fail: up_read(&minor_rwsem); mutex_unlock(&dvbdev_mutex); return -ENODEV; }
void * osi_UFSOpen(afs_int32 ainode) { register struct osi_file *afile = NULL; extern int cacheDiskType; afs_int32 code = 0; struct inode *tip = NULL; struct file *filp = NULL; AFS_STATCNT(osi_UFSOpen); if (cacheDiskType != AFS_FCACHE_TYPE_UFS) { osi_Panic("UFSOpen called for non-UFS cache\n"); } if (!afs_osicred_initialized) { /* valid for alpha_osf, SunOS, Ultrix */ memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED)); crhold(&afs_osi_cred); /* don't let it evaporate, since it is static */ afs_osicred_initialized = 1; } afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file)); AFS_GUNLOCK(); if (!afile) { osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n", sizeof(struct osi_file)); } memset(afile, 0, sizeof(struct osi_file)); filp = &afile->file; filp->f_dentry = &afile->dentry; tip = iget(afs_cacheSBp, (u_long) ainode); if (!tip) osi_Panic("Can't get inode %d\n", ainode); FILE_INODE(filp) = tip; tip->i_flags |= MS_NOATIME; /* Disable updating access times. */ filp->f_flags = O_RDWR; #if defined(AFS_LINUX24_ENV) filp->f_mode = FMODE_READ|FMODE_WRITE; filp->f_op = fops_get(tip->i_fop); #else filp->f_op = tip->i_op->default_file_ops; #endif if (filp->f_op && filp->f_op->open) code = filp->f_op->open(tip, filp); if (code) osi_Panic("Can't open inode %d\n", ainode); afile->size = i_size_read(tip); AFS_GLOCK(); afile->offset = 0; afile->proc = (int (*)())0; afile->inum = ainode; /* for hint validity checking */ return (void *)afile; }
static int soundcore_open(struct inode *inode, struct file *file) { int chain; int unit = iminor(inode); struct sound_unit *s; const struct file_operations *new_fops = NULL; lock_kernel (); chain=unit&0x0F; if(chain==4 || chain==5) /* dsp/audio/dsp16 */ { unit&=0xF0; unit|=3; chain=3; } spin_lock(&sound_loader_lock); s = __look_for_unit(chain, unit); if (s) new_fops = fops_get(s->unit_fops); if (!new_fops) { spin_unlock(&sound_loader_lock); /* * Please, don't change this order or code. * For ALSA slot means soundcard and OSS emulation code * comes as add-on modules which aren't depend on * ALSA toplevel modules for soundcards, thus we need * load them at first. [Jaroslav Kysela <*****@*****.**>] */ request_module("sound-slot-%i", unit>>4); request_module("sound-service-%i-%i", unit>>4, chain); spin_lock(&sound_loader_lock); s = __look_for_unit(chain, unit); if (s) new_fops = fops_get(s->unit_fops); }
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; struct inode *inode; int error; error = -ENFILE; f = get_empty_filp(); if (!f) goto cleanup_dentry; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); if (inode->i_sb) file_move(f, &inode->i_sb->s_files); if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *vperfctr_get_filp(void) { struct file *filp; struct inode *inode; struct dentry *dentry; inode = vperfctr_get_inode(); if (!inode) goto out; dentry = vperfctr_d_alloc_root(inode); if (!dentry) goto out_inode; /* * Create the filp _after_ the inode and dentry, to avoid * needing access to put_filp(), which is no longer exported * starting with kernel 2.6.10-rc1. fput() is available but * doesn't work on incomplete files. We now need access to * dput() instead, but that's Ok. */ filp = get_empty_filp(); if (!filp) goto out_dentry; filp_vfsmnt(filp) = mntget(vperfctr_mnt); filp_dentry(filp) = dentry; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2) filp->f_mapping = dentry->d_inode->i_mapping; #endif filp->f_pos = 0; filp->f_flags = 0; filp->f_op = fops_get(&vperfctr_file_ops); /* fops_get() for MODULE */ filp->f_mode = FMODE_READ; filp->f_version = 0; return filp; out_dentry: dput(dentry); goto out; /* dput() also does iput() */ out_inode: iput(inode); out: return NULL; }
/* * fifo_open: - open a fifo device node * @inode: the external filesystem inode * @file: the external filesystem file pointer * * fifo_open() is only used to open a fifo device (named pipe) from a character device node in an * external filesystem. This is never called for direct opens of a specfs device node (for direct * opens, see spec_dev_open() in strspecfs.c). The character device inode is opened directly and * no inode in the shadow filesystem is addressed. */ STATIC int fifo_open(struct inode *inode, struct file *file) { int err; dev_t dev = makedevice(fifo_cdev.d_modid, 0); { struct file_operations *f_op; err = -ENXIO; if (!(f_op = fops_get(fifo_cdev.d_fop))) { goto error; } fops_put(file->f_op); file->f_op = f_op; } file->private_data = &dev; /* use this device number instead of inode number */ file->f_flags &= ~O_CLONE; /* FIFOs never clone */ err = file->f_op->open(inode, file); error: return (err); }
static int do_dentry_open(struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { static const struct file_operations empty_fops = {}; struct inode *inode; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; if (unlikely(f->f_flags & O_PATH)) f->f_mode = FMODE_PATH; path_get(&f->f_path); inode = f->f_inode = f->f_path.dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, f->f_path.mnt); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) file_take_write(f); } f->f_mapping = inode->i_mapping; file_sb_list_add(f, inode->i_sb); if (unlikely(f->f_mode & FMODE_PATH)) { f->f_op = &empty_fops; return 0; } f->f_op = fops_get(inode->i_fop); error = security_file_open(f, cred); if (error) goto cleanup_all; error = break_lease(inode, f->f_flags); if (error) goto cleanup_all; if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); return 0; cleanup_all: fops_put(f->f_op); file_sb_list_del(f); if (f->f_mode & FMODE_WRITE) { put_write_access(inode); if (!special_file(inode->i_mode)) { /* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */ file_reset_write(f); __mnt_drop_write(f->f_path.mnt); } } cleanup_file: path_put(&f->f_path); f->f_path.mnt = NULL; f->f_path.dentry = NULL; f->f_inode = NULL; return error; }
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; struct inode *inode; static LIST_HEAD(kill_list); int error; error = -ENFILE; f = get_empty_filp(); if (!f) goto cleanup_dentry; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); /* preallocate kiobuf for O_DIRECT */ f->f_iobuf = NULL; f->f_iobuf_lock = 0; if (f->f_flags & O_DIRECT) { error = alloc_kiovec(1, &f->f_iobuf); if (error) goto cleanup_all; } if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); return f; cleanup_all: if (f->f_iobuf) free_kiovec(1, &f->f_iobuf); fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_move(f, &kill_list); /* out of the way.. */ f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, struct file *f, int (*open)(struct inode *, struct file *)) { struct inode *inode; int error; f->f_flags = flags; f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, mnt); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) file_take_write(f); } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); error = security_dentry_open(f); if (error) goto cleanup_all; if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_mem))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) { put_write_access(inode); if (!special_file(inode->i_mode)) { /* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */ file_reset_write(f); mnt_drop_write(mnt); } } file_kill(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, struct file *f, int (*open)(struct inode *, struct file *)) { struct inode *inode; int error; f->f_flags = flags; f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_page))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_kill(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, struct file *f) { struct inode *inode; static LIST_HEAD(kill_list); int error; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); /* preallocate kiobuf for O_DIRECT */ f->f_iobuf = NULL; f->f_iobuf_lock = 0; if (f->f_flags & O_DIRECT) { error = alloc_kiovec(1, &f->f_iobuf); if (error) goto cleanup_all; } if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!inode->i_mapping || !inode->i_mapping->a_ops || !(inode->i_mapping->a_ops->direct_IO || inode->i_mapping->a_ops->direct_sector_IO)) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: if (f->f_iobuf) free_kiovec(1, &f->f_iobuf); fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_move(f, &kill_list); /* out of the way.. */ f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
static struct file *__dentry_open(struct _dentry *dentry, struct vfsmount *mnt, int flags, struct file *f, int (*open)(struct _inode *, struct file *)) { struct _inode *inode; int error; struct super_block *sb; struct _file *_f = tx_cache_get_file(f); _f->f_flags = flags; _f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = d_get_inode(dentry); sb = inode->i_sb; if (_f->f_mode & FMODE_WRITE) { error = get_write_access(parent(inode)); if (error) goto cleanup_file; } f->f_mapping = inode->i_mapping; _f->f_path.dentry = parent(dentry); _f->f_path.mnt = mnt; _f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &sb->s_files); if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } _f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, tx_cache_get_inode(f->f_mapping->host)->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (_f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_page))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (_f->f_mode & FMODE_WRITE) put_write_access(parent(inode)); file_kill(f); _f->f_path.dentry = NULL; _f->f_path.mnt = NULL; cleanup_file: /* Avoid issues if we recycle this object */ if(live_transaction()) early_release(&f->xobj, 1); put_filp(f); dput(parent(dentry)); mntput(mnt); return ERR_PTR(error); }
static int do_dentry_open(struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { static const struct file_operations empty_fops = {}; struct inode *inode; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; path_get(&f->f_path); inode = f->f_inode = f->f_path.dentry->d_inode; f->f_mapping = inode->i_mapping; if (unlikely(f->f_flags & O_PATH)) { f->f_mode = FMODE_PATH; f->f_op = &empty_fops; return 0; } if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { error = get_write_access(inode); if (unlikely(error)) goto cleanup_file; error = __mnt_want_write(f->f_path.mnt); if (unlikely(error)) { put_write_access(inode); goto cleanup_file; } f->f_mode |= FMODE_WRITER; } /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ if (S_ISREG(inode->i_mode)) f->f_mode |= FMODE_ATOMIC_POS; f->f_op = fops_get(inode->i_fop); if (unlikely(WARN_ON(!f->f_op))) { error = -ENODEV; goto cleanup_all; } error = security_file_open(f, cred); if (error) goto cleanup_all; error = break_lease(inode, f->f_flags); if (error) goto cleanup_all; if (!open) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); if ((f->f_mode & FMODE_READ) && likely(f->f_op->read || f->f_op->aio_read || f->f_op->read_iter)) f->f_mode |= FMODE_CAN_READ; if ((f->f_mode & FMODE_WRITE) && likely(f->f_op->write || f->f_op->aio_write || f->f_op->write_iter)) f->f_mode |= FMODE_CAN_WRITE; f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); return 0; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITER) { put_write_access(inode); __mnt_drop_write(f->f_path.mnt); } cleanup_file: path_put(&f->f_path); f->f_path.mnt = NULL; f->f_path.dentry = NULL; f->f_inode = NULL; return error; }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { static const struct file_operations empty_fops = {}; struct inode *inode; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; if (unlikely(f->f_flags & O_PATH)) f->f_mode = FMODE_PATH; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, mnt); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) file_take_write(f); } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; file_sb_list_add(f, inode->i_sb); if (unlikely(f->f_mode & FMODE_PATH)) { f->f_op = &empty_fops; return f; } f->f_op = fops_get(inode->i_fop); error = security_dentry_open(f, cred); if (error) goto cleanup_all; error = break_lease(inode, f->f_flags); if (error) goto cleanup_all; if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_mem))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) { put_write_access(inode); if (!special_file(inode->i_mode)) { /* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */ file_reset_write(f); mnt_drop_write(mnt); } } file_sb_list_del(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
extern int vnode_shadow_fop_open( INODE_T *inode, FILE_T *file ) { int err = 0; INODE_T *real_inode; DENT_T *rdentry = NULL; DENT_T *oldent; struct file_operations *oldfops; struct vfsmount *oldmnt, *newmnt; VNODE_T *cvp; oldmnt = file->f_vfsmnt; oldent = file->f_dentry; ASSERT(D_COUNT(oldent)); /* The Linux kernel has stopped ignoring the O_DIRECT flag. * The problem is that they wait until after they call the fop open * function to check the inode to see if it will support direct I/O. * But they get the inode pointer before they call us and check the * inode after we return so they never check the actual inode we open * but only the shadow one. Their error handling never comes back to * us and they release their old pointers and not our new ones. The * only choice we have is to not allow O_DIRECT on shadow files. */ if (file->f_flags & O_DIRECT) { err = -EINVAL; goto out_nolock; } /* Get the real dentry */ rdentry = REALDENTRY_LOCKED(oldent, &cvp); if (rdentry == NULL) { err = -ENOENT; goto out_nolock; } VNODE_DGET(rdentry); /* protect rdentry->d_inode */ if (rdentry->d_inode == NULL) { /* delete race */ err = -ENOENT; goto out; } newmnt = MDKI_MNTGET(REALVFSMNT(oldent)); if (newmnt == NULL) { err = -EOPNOTSUPP; /* XXX */ goto out; } /* Check that we can write to this file. Clean up the count on the * shadow inode. */ if (file->f_mode & FMODE_WRITE) { err = get_write_access(rdentry->d_inode); if (err) { MDKI_MNTPUT(newmnt); goto out; } } real_inode = rdentry->d_inode; /* * Swap the file structure contents to point at the underlying object. */ /* In Linux 2.6 they added the mapping stuff to the file so we have to set ** that up here, too. */ file->f_mapping = real_inode->i_mapping; VNLAYER_RA_STATE_INIT(&(file->f_ra), file->f_mapping); file->f_dentry = VNODE_DGET(rdentry); oldfops = file->f_op; file->f_vfsmnt = newmnt; file->f_op = fops_get(real_inode->i_fop); if (real_inode->i_fop && !file->f_op) /* If we failed to get the reference to a non-NULL op, bail out */ err = -EIO; /* XXX? better error code */ if (!err) { /* Move the file to the file list for the real superblock * and remove it from the shadow list */ /* It would be better to use file_move() but it's not exported */ file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &real_inode->i_sb->s_files); file_list_unlock(); if (file->f_op && file->f_op->open) { err = (*file->f_op->open)(real_inode, file); if (err) { /* restore our file to the list on our super block */ file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &oldent->d_inode->i_sb->s_files); file_list_unlock(); } } } if (err) { /* MUST put back old dentry/fops to get accounting right in upper * layer. */ put_write_access(rdentry->d_inode); if (file->f_dentry) VNODE_DPUT(file->f_dentry); if (file->f_op) fops_put(file->f_op); MDKI_MNTPUT(file->f_vfsmnt); file->f_vfsmnt = oldmnt; file->f_dentry = oldent; file->f_op = oldfops; } else { put_write_access(oldent->d_inode); VNODE_DPUT(oldent); /* Drop reference now that we've dropped our use of the file ops */ fops_put(oldfops); MDKI_MNTPUT(oldmnt); } out: VNODE_DPUT(rdentry); REALDENTRY_UNLOCK(oldent, cvp); out_nolock: MDKI_TRACE(TRACE_OPEN, "%s: opened vp=%p fp=%p rdent=%p rdcnt=%d fcnt=%d" ", err %d\n", __func__, inode, file, rdentry, rdentry ? D_COUNT(rdentry) : 0, F_COUNT(file), -err); return(err); }