// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
*/
/** * gfs2_set_iop - Sets inode operations * @inode: The inode with correct i_mode filled in * * GFS2 lookup code fills in vfs inode contents based on info obtained * from directory entry inside gfs2_inode_lookup().
*/
/** * gfs2_inode_lookup - Lookup an inode * @sb: The super block * @type: The type of the inode * @no_addr: The inode number * @no_formal_ino: The inode generation number * @blktype: Requested block type (GFS2_BLKST_DINODE or GFS2_BLKST_UNLINKED; * GFS2_BLKST_FREE to indicate not to verify) * * If @type is DT_UNKNOWN, the inode type is fetched from disk. * * If @blktype is anything other than GFS2_BLKST_FREE (which is used as a * placeholder because it doesn't otherwise make sense), the on-disk block type * is verified to be @blktype. * * When @no_formal_ino is non-zero, this function will return ERR_PTR(-ESTALE) * if it detects that @no_formal_ino doesn't match the actual inode generation * number. However, it doesn't always know unless @type is DT_UNKNOWN. * * Returns: A VFS inode, or an error
*/
/* * The only caller that sets @blktype to GFS2_BLKST_UNLINKED is * delete_work_func(). Make sure not to cancel the delete work * from within itself here.
*/ if (blktype == GFS2_BLKST_UNLINKED)
extra_flags |= LM_FLAG_TRY; else
gfs2_cancel_delete_work(io_gl);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED,
GL_EXACT | GL_NOPID | extra_flags,
&ip->i_iopen_gh);
gfs2_glock_put(io_gl); if (unlikely(error)) goto fail;
if (type == DT_UNKNOWN || blktype != GFS2_BLKST_FREE) { /* * The GL_SKIP flag indicates to skip reading the inode * block. We read the inode when instantiating it * after possibly checking the block type.
*/
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE,
GL_SKIP, &i_gh); if (error) goto fail;
error = -ESTALE; if (no_formal_ino &&
gfs2_inode_already_deleted(ip->i_gl, no_formal_ino)) goto fail;
if (blktype != GFS2_BLKST_FREE) {
error = gfs2_check_blk_type(sdp, no_addr,
blktype); if (error) goto fail;
}
}
/* Lowest possible timestamp; will be overwritten in gfs2_dinode_in. */
inode_set_atime(inode,
1LL << (8 * sizeof(inode_get_atime_sec(inode)) - 1),
0);
glock_set_object(ip->i_gl, ip);
if (type == DT_UNKNOWN) { /* Inode glock must be locked already */
error = gfs2_instantiate(&i_gh); if (error) {
glock_clear_object(ip->i_gl, ip); goto fail;
}
} else {
ip->i_no_formal_ino = no_formal_ino;
inode->i_mode = DT2IF(type);
}
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
fail: if (error == GLR_TRYFAILED)
error = -EAGAIN; if (gfs2_holder_initialized(&ip->i_iopen_gh))
gfs2_glock_dq_uninit(&ip->i_iopen_gh); if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh); if (ip->i_gl) {
gfs2_glock_put(ip->i_gl);
ip->i_gl = NULL;
}
iget_failed(inode); return ERR_PTR(error);
}
/** * gfs2_lookup_by_inum - look up an inode by inode number * @sdp: The super block * @no_addr: The inode number * @no_formal_ino: The inode generation number (0 for any) * @blktype: Requested block type (see gfs2_inode_lookup)
*/ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
u64 no_formal_ino, unsignedint blktype)
{ struct super_block *sb = sdp->sd_vfs; struct inode *inode; int error;
if (no_formal_ino) {
error = -EIO; if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) goto fail_iput;
} return inode;
fail_iput:
iput(inode); return ERR_PTR(error);
}
/** * gfs2_lookup_meta - Look up an inode in a metadata directory * @dip: The directory * @name: The name of the inode
*/ struct inode *gfs2_lookup_meta(struct inode *dip, constchar *name)
{ struct qstr qstr; struct inode *inode;
/* * Must not call back into the filesystem when allocating * pages in the metadata inode's address space.
*/
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
return inode;
}
/** * gfs2_lookupi - Look up a filename in a directory and return its inode * @dir: The inode of the directory containing the inode to look-up * @name: The name of the inode to look for * @is_root: If 1, ignore the caller's permissions * * This can be called via the VFS filldir function when NFS is doing * a readdirplus and the inode which its intending to stat isn't * already in cache. In this case we must not take the directory glock * again, since the readdir call will have already taken that lock. * * Returns: errno
*/
if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) {
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); if (error) return ERR_PTR(error);
}
if (!is_root) {
error = gfs2_permission(&nop_mnt_idmap, dir, MAY_EXEC); if (error) goto out;
}
inode = gfs2_dir_search(dir, name, false); if (IS_ERR(inode))
error = PTR_ERR(inode);
out: if (gfs2_holder_initialized(&d_gh))
gfs2_glock_dq_uninit(&d_gh); if (error == -ENOENT) return NULL; return inode ? inode : ERR_PTR(error);
}
/** * create_ok - OK to create a new on-disk inode here? * @dip: Directory in which dinode is to be created * @name: Name of new dinode * @mode: * * Returns: errno
*/
/** * gfs2_init_xattr - Initialise an xattr block for a new inode * @ip: The inode in question * * This sets up an empty xattr block for a new inode, ready to * take any ACLs, LSM xattrs, etc.
*/
/** * init_dinode - Fill in a new dinode structure * @dip: The directory this inode is being created in * @ip: The inode * @symname: The symlink destination (if a symlink) *
*/
switch(ip->i_inode.i_mode & S_IFMT) { case S_IFDIR:
gfs2_init_dir(dibh, dip); break; case S_IFLNK:
memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, ip->i_inode.i_size); break;
}
set_buffer_uptodate(dibh);
brelse(dibh);
}
/** * gfs2_trans_da_blks - Calculate number of blocks to link inode * @dip: The directory we are linking into * @da: The dir add information * @nr_inodes: The number of inodes involved * * This calculate the number of blocks we need to reserve in a * transaction to link @nr_inodes into a directory. In most cases * @nr_inodes will be 2 (the directory plus the inode being linked in) * but in case of rename, 4 may be required. * * Returns: Number of blocks
*/
/** * gfs2_create_inode - Create a new inode * @dir: The parent directory * @dentry: The new dentry * @file: If non-NULL, the file which is being opened * @mode: The permissions on the new inode * @dev: For device nodes, this is the device number * @symname: For symlinks, this is the link destination * @size: The initial size of the inode (ignored for directories) * @excl: Force fail if inode exists * * FIXME: Change to allocate the disk blocks and write them out in the same * transaction. That way, we can no longer end up in a situation in which an * inode is allocated, the node crashes, and the block looks like a valid * inode. (With atomic creates in place, we will also no longer need to zero * the link count and dirty the inode here on failure.) * * Returns: 0 on success, or error code
*/
error = link_dinode(dip, name, ip, &da); if (error) goto fail_gunlock4;
mark_inode_dirty(inode);
d_instantiate(dentry, inode); /* After instantiate, errors should result in evict which will destroy
* both inode and iopen glocks properly. */ if (file) {
file->f_mode |= FMODE_CREATED;
error = finish_open(file, dentry, gfs2_open_common);
}
gfs2_glock_dq_uninit(&d_gh);
gfs2_qa_put(ip);
gfs2_glock_dq_uninit(&gh);
gfs2_glock_put(io_gl);
gfs2_qa_put(dip);
unlock_new_inode(inode); return error;
/** * gfs2_create - Create a file * @idmap: idmap of the mount the inode was found from * @dir: The directory in which to create the file * @dentry: The dentry of the new file * @mode: The mode of the new file * @excl: Force fail if inode exists * * Returns: errno
*/
/** * __gfs2_lookup - Look up a filename in a directory and return its inode * @dir: The directory inode * @dentry: The dentry of the new inode * @file: File to be opened * * * Returns: errno
*/
/** * gfs2_link - Link to a file * @old_dentry: The inode to link * @dir: Add link to this directory * @dentry: The name of the link * * Link the inode in "old_dentry" into the directory "dir" with the * name in "dentry". * * Returns: errno
*/
/* * gfs2_unlink_ok - check to see that a inode is still in a directory * @dip: the directory * @name: the name of the file * @ip: the inode * * Assumes that the lock on (at least) @dip is held. * * Returns: 0 if the parent/child relationship is correct, errno if it isn't
*/
/** * gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it * @dip: The parent directory * @dentry: The dentry to unlink * * Called with all the locks and in a transaction. This will only be * called for a directory after it has been checked to ensure it is empty. * * Returns: 0 on success, or an error
*/
error = gfs2_dir_del(dip, dentry); if (error) return error;
ip->i_entries = 0;
inode_set_ctime_current(inode); if (S_ISDIR(inode->i_mode))
clear_nlink(inode); else
drop_nlink(inode);
mark_inode_dirty(inode); if (inode->i_nlink == 0)
gfs2_unlink_di(inode); return 0;
}
/** * gfs2_unlink - Unlink an inode (this does rmdir as well) * @dir: The inode of the directory containing the inode to unlink * @dentry: The file itself * * This routine uses the type of the inode as a flag to figure out * whether this is an unlink or an rmdir. * * Returns: errno
*/
/** * gfs2_symlink - Create a symlink * @idmap: idmap of the mount the inode was found from * @dir: The directory to create the symlink in * @dentry: The dentry to put the symlink in * @symname: The thing which the link points to * * Returns: errno
*/
/** * gfs2_mkdir - Make a directory * @idmap: idmap of the mount the inode was found from * @dir: The parent directory of the new one * @dentry: The dentry of the new directory * @mode: The mode of the new directory * * Returns: the dentry, or ERR_PTR(errno)
*/
/** * gfs2_mknod - Make a special file * @idmap: idmap of the mount the inode was found from * @dir: The directory in which the special file will reside * @dentry: The dentry of the special file * @mode: The mode of the special file * @dev: The device specification of the special file *
*/
/** * gfs2_atomic_open - Atomically open a file * @dir: The directory * @dentry: The proposed new entry * @file: The proposed new struct file * @flags: open flags * @mode: File mode * * Returns: error code or 0 for success
*/
/* * gfs2_ok_to_move - check if it's ok to move a directory to another directory * @this: move this * @to: to here * * Follow @to back to the root and make sure we don't encounter @this * Assumes we already hold the rename lock. * * Returns: errno
*/
/** * update_moved_ino - Update an inode that's being moved * @ip: The inode being moved * @ndip: The parent directory of the new filename * @dir_rename: True of ip is a directory * * Returns: errno
*/
staticint update_moved_ino(struct gfs2_inode *ip, struct gfs2_inode *ndip, int dir_rename)
{ if (dir_rename) return gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);
/** * gfs2_rename - Rename a file * @odir: Parent directory of old file name * @odentry: The old dentry of the file * @ndir: Parent directory of new file name * @ndentry: The new dentry of the file * * Returns: errno
*/
gfs2_holder_mark_uninitialized(&r_gh);
gfs2_holder_mark_uninitialized(&rd_gh); if (d_really_is_positive(ndentry)) {
nip = GFS2_I(d_inode(ndentry)); if (ip == nip) return 0;
}
error = gfs2_rindex_update(sdp); if (error) return error;
error = gfs2_qa_get(ndip); if (error) return error;
if (odip != ndip) {
error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
0, &r_gh); if (error) goto out;
if (S_ISDIR(ip->i_inode.i_mode)) {
dir_rename = 1; /* don't move a directory into its subdir */
error = gfs2_ok_to_move(ip, ndip); if (error) goto out_gunlock_r;
}
}
for (x = 0; x < num_gh; x++) {
error = gfs2_glock_nq(ghs + x); if (error) goto out_gunlock;
}
error = gfs2_glock_async_wait(num_gh, ghs); if (error) goto out_gunlock;
if (nip) { /* Grab the resource group glock for unlink flag twiddling. * This is the case where the target dinode already exists * so we unlink before doing the rename.
*/
nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr, 1); if (!nrgd) {
error = -ENOENT; goto out_gunlock;
}
error = gfs2_glock_nq_init(nrgd->rd_gl, LM_ST_EXCLUSIVE,
LM_FLAG_NODE_SCOPE, &rd_gh); if (error) goto out_gunlock;
}
error = -ENOENT; if (ip->i_inode.i_nlink == 0) goto out_gunlock;
/* Check out the old directory */
error = gfs2_unlink_ok(odip, &odentry->d_name, ip); if (error) goto out_gunlock;
/* Check out the new directory */
if (nip) {
error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); if (error) goto out_gunlock;
if (nip)
error = gfs2_unlink_inode(ndip, ndentry);
error = update_moved_ino(ip, ndip, dir_rename); if (error) goto out_end_trans;
error = gfs2_dir_del(odip, odentry); if (error) goto out_end_trans;
error = gfs2_dir_add(ndir, &ndentry->d_name, ip, &da); if (error) goto out_end_trans;
out_end_trans:
gfs2_trans_end(sdp);
out_ipreserv: if (da.nr_blocks)
gfs2_inplace_release(ndip);
out_gunlock_q: if (da.nr_blocks)
gfs2_quota_unlock(ndip);
out_gunlock:
gfs2_dir_no_add(&da); if (gfs2_holder_initialized(&rd_gh))
gfs2_glock_dq_uninit(&rd_gh);
while (x--) { if (gfs2_holder_queued(ghs + x))
gfs2_glock_dq(ghs + x);
gfs2_holder_uninit(ghs + x);
}
out_gunlock_r: if (gfs2_holder_initialized(&r_gh))
gfs2_glock_dq_uninit(&r_gh);
out:
gfs2_qa_put(ndip); return error;
}
/** * gfs2_exchange - exchange two files * @odir: Parent directory of old file name * @odentry: The old dentry of the file * @ndir: Parent directory of new file name * @ndentry: The new dentry of the file * @flags: The rename flags * * Returns: errno
*/
/** * gfs2_get_link - Follow a symbolic link * @dentry: The dentry of the link * @inode: The inode of the link * @done: destructor for return value * * This can handle symlinks of any size. * * Returns: 0 on success or error code
*/
/** * gfs2_permission * @idmap: idmap of the mount the inode was found from * @inode: The inode * @mask: The mask to be tested * * This may be called from the VFS directly, or from within GFS2 with the * inode locked, so we look to see if the glock is already locked and only * lock the glock if its not already been done. * * Returns: errno
*/
int gfs2_permission(struct mnt_idmap *idmap, struct inode *inode, int mask)
{ int may_not_block = mask & MAY_NOT_BLOCK; struct gfs2_inode *ip; struct gfs2_holder i_gh; struct gfs2_glock *gl; int error;
gfs2_holder_mark_uninitialized(&i_gh);
ip = GFS2_I(inode);
gl = rcu_dereference_check(ip->i_gl, !may_not_block); if (unlikely(!gl)) { /* inode is getting torn down, must be RCU mode */
WARN_ON_ONCE(!may_not_block); return -ECHILD;
} if (gfs2_glock_is_locked_by_me(gl) == NULL) { if (may_not_block) return -ECHILD;
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error;
}
if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
error = -EPERM; else
error = generic_permission(&nop_mnt_idmap, inode, mask); if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
/** * gfs2_setattr - Change attributes on an inode * @idmap: idmap of the mount the inode was found from * @dentry: The dentry which is changing * @attr: The structure describing the change * * The VFS layer wants to change one or more of an inodes attributes. Write * that change out to disk. * * Returns: errno
*/
error: if (!error)
mark_inode_dirty(inode);
gfs2_glock_dq_uninit(&i_gh);
out:
gfs2_qa_put(ip); return error;
}
/** * gfs2_getattr - Read out an inode's attributes * @idmap: idmap of the mount the inode was found from * @path: Object to query * @stat: The inode's stats * @request_mask: Mask of STATX_xxx flags indicating the caller's interests * @flags: AT_STATX_xxx setting * * This may be called from the VFS directly, or from within GFS2 with the * inode locked, so we look to see if the glock is already locked and only * lock the glock if its not already been done. Note that its the NFS * readdirplus operation which causes this to be called (from filldir) * with the glock already held. * * Returns: errno
*/
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.