📄 inode.c
字号:
/* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. */#include <linux/sched.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/buffer_head.h>#include <linux/posix_acl.h>#include <linux/sort.h>#include <linux/gfs2_ondisk.h>#include <linux/crc32.h>#include <linux/lm_interface.h>#include <linux/security.h>#include "gfs2.h"#include "incore.h"#include "acl.h"#include "bmap.h"#include "dir.h"#include "eattr.h"#include "glock.h"#include "glops.h"#include "inode.h"#include "log.h"#include "meta_io.h"#include "ops_address.h"#include "ops_file.h"#include "ops_inode.h"#include "quota.h"#include "rgrp.h"#include "trans.h"#include "util.h"struct gfs2_inum_range_host { u64 ir_start; u64 ir_length;};static int iget_test(struct inode *inode, void *opaque){ struct gfs2_inode *ip = GFS2_I(inode); u64 *no_addr = opaque; if (ip->i_no_addr == *no_addr && inode->i_private != NULL) return 1; return 0;}static int iget_set(struct inode *inode, void *opaque){ struct gfs2_inode *ip = GFS2_I(inode); u64 *no_addr = opaque; inode->i_ino = (unsigned long)*no_addr; ip->i_no_addr = *no_addr; return 0;}struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr){ unsigned long hash = (unsigned long)no_addr; return ilookup5(sb, hash, iget_test, &no_addr);}static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr){ unsigned long hash = (unsigned long)no_addr; return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);}struct gfs2_skip_data { u64 no_addr; int skipped;};static int iget_skip_test(struct inode *inode, void *opaque){ struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_skip_data *data = opaque; if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){ if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ data->skipped = 1; return 0; } return 1; } return 0;}static int iget_skip_set(struct inode *inode, void *opaque){ struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_skip_data *data = opaque; if (data->skipped) return 1; inode->i_ino = (unsigned long)(data->no_addr); ip->i_no_addr = data->no_addr; return 0;}static struct inode *gfs2_iget_skip(struct super_block *sb, u64 no_addr){ struct gfs2_skip_data data; unsigned long hash = (unsigned long)no_addr; data.no_addr = no_addr; data.skipped = 0; return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data);}/** * GFS2 lookup code fills in vfs inode contents based on info obtained * from directory entry inside gfs2_inode_lookup(). This has caused issues * with NFS code path since its get_dentry routine doesn't have the relevant * directory entry when gfs2_inode_lookup() is invoked. Part of the code * segment inside gfs2_inode_lookup code needs to get moved around. * * Clean up I_LOCK and I_NEW as well. **/void gfs2_set_iop(struct inode *inode){ umode_t mode = inode->i_mode; if (S_ISREG(mode)) { inode->i_op = &gfs2_file_iops; inode->i_fop = &gfs2_file_fops; inode->i_mapping->a_ops = &gfs2_file_aops; } else if (S_ISDIR(mode)) { inode->i_op = &gfs2_dir_iops; inode->i_fop = &gfs2_dir_fops; } else if (S_ISLNK(mode)) { inode->i_op = &gfs2_symlink_iops; } else { inode->i_op = &gfs2_dev_iops; } unlock_new_inode(inode);}/** * gfs2_inode_lookup - Lookup an inode * @sb: The super block * @no_addr: The inode number * @type: The type of the inode * @skip_freeing: set this not return an inode if it is currently being freed. * * Returns: A VFS inode, or an error */struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, u64 no_addr, u64 no_formal_ino, int skip_freeing){ struct inode *inode; struct gfs2_inode *ip; struct gfs2_glock *io_gl; int error; if (skip_freeing) inode = gfs2_iget_skip(sb, no_addr); else inode = gfs2_iget(sb, no_addr); ip = GFS2_I(inode); if (!inode) return ERR_PTR(-ENOBUFS); if (inode->i_state & I_NEW) { struct gfs2_sbd *sdp = GFS2_SB(inode); inode->i_private = ip; ip->i_no_formal_ino = no_formal_ino; error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); if (unlikely(error)) goto fail; ip->i_gl->gl_object = ip; error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); if (unlikely(error)) goto fail_put; set_bit(GIF_INVALID, &ip->i_flags); error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); if (unlikely(error)) goto fail_iopen; ip->i_iopen_gh.gh_gl->gl_object = ip; gfs2_glock_put(io_gl); if ((type == DT_UNKNOWN) && (no_formal_ino == 0)) goto gfs2_nfsbypass; inode->i_mode = DT2IF(type); /* * We must read the inode in order to work out its type in * this case. Note that this doesn't happen often as we normally * know the type beforehand. This code path only occurs during * unlinked inode recovery (where it is safe to do this glock, * which is not true in the general case). */ if (type == DT_UNKNOWN) { struct gfs2_holder gh; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); if (unlikely(error)) goto fail_glock; /* Inode is now uptodate */ gfs2_glock_dq_uninit(&gh); } gfs2_set_iop(inode); }gfs2_nfsbypass: return inode;fail_glock: gfs2_glock_dq(&ip->i_iopen_gh);fail_iopen: gfs2_glock_put(io_gl);fail_put: ip->i_gl->gl_object = NULL; gfs2_glock_put(ip->i_gl);fail: iput(inode); return ERR_PTR(error);}static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf){ struct gfs2_dinode_host *di = &ip->i_di; const struct gfs2_dinode *str = buf; if (ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); return -EIO; } ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); ip->i_inode.i_mode = be32_to_cpu(str->di_mode); ip->i_inode.i_rdev = 0; switch (ip->i_inode.i_mode & S_IFMT) { case S_IFBLK: case S_IFCHR: ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), be32_to_cpu(str->di_minor)); break; }; ip->i_inode.i_uid = be32_to_cpu(str->di_uid); ip->i_inode.i_gid = be32_to_cpu(str->di_gid); /* * We will need to review setting the nlink count here in the * light of the forthcoming ro bind mount work. This is a reminder * to do that. */ ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); di->di_size = be64_to_cpu(str->di_size); i_size_write(&ip->i_inode, di->di_size); di->di_blocks = be64_to_cpu(str->di_blocks); gfs2_set_inode_blocks(&ip->i_inode); ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime); ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec); ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); di->di_goal_meta = be64_to_cpu(str->di_goal_meta); di->di_goal_data = be64_to_cpu(str->di_goal_data); di->di_generation = be64_to_cpu(str->di_generation); di->di_flags = be32_to_cpu(str->di_flags); gfs2_set_inode_flags(&ip->i_inode); di->di_height = be16_to_cpu(str->di_height); di->di_depth = be16_to_cpu(str->di_depth); di->di_entries = be32_to_cpu(str->di_entries); di->di_eattr = be64_to_cpu(str->di_eattr); return 0;}static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh){ ip->i_cache[0] = bh;}/** * gfs2_inode_refresh - Refresh the incore copy of the dinode * @ip: The GFS2 inode * * Returns: errno */int gfs2_inode_refresh(struct gfs2_inode *ip){ struct buffer_head *dibh; int error; error = gfs2_meta_inode_buffer(ip, &dibh); if (error) return error; if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) { brelse(dibh); return -EIO; } error = gfs2_dinode_in(ip, dibh->b_data); brelse(dibh); clear_bit(GIF_INVALID, &ip->i_flags); return error;}int gfs2_dinode_dealloc(struct gfs2_inode *ip){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; struct gfs2_rgrpd *rgd; int error; if (ip->i_di.di_blocks != 1) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); return -EIO; } al = gfs2_alloc_get(ip); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out; error = gfs2_rindex_hold(sdp, &al->al_ri_gh); if (error) goto out_qs; rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); if (!rgd) { gfs2_consist_inode(ip); error = -EIO; goto out_rindex_relse; } error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &al->al_rgd_gh); if (error) goto out_rindex_relse; error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); if (error) goto out_rg_gunlock; gfs2_trans_add_gl(ip->i_gl); gfs2_free_di(rgd, ip); gfs2_trans_end(sdp); clear_bit(GLF_STICKY, &ip->i_gl->gl_flags);out_rg_gunlock: gfs2_glock_dq_uninit(&al->al_rgd_gh);out_rindex_relse: gfs2_glock_dq_uninit(&al->al_ri_gh);out_qs: gfs2_quota_unhold(ip);out: gfs2_alloc_put(ip); return error;}/** * gfs2_change_nlink - Change nlink count on inode * @ip: The GFS2 inode * @diff: The change in the nlink count required * * Returns: errno */int gfs2_change_nlink(struct gfs2_inode *ip, int diff){ struct buffer_head *dibh; u32 nlink; int error; BUG_ON(diff != 1 && diff != -1); nlink = ip->i_inode.i_nlink + diff; /* If we are reducing the nlink count, but the new value ends up being bigger than the old one, we must have underflowed. */ if (diff < 0 && nlink > ip->i_inode.i_nlink) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); return -EIO; } error = gfs2_meta_inode_buffer(ip, &dibh); if (error) return error; if (diff > 0) inc_nlink(&ip->i_inode); else drop_nlink(&ip->i_inode); ip->i_inode.i_ctime = CURRENT_TIME; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); mark_inode_dirty(&ip->i_inode); if (ip->i_inode.i_nlink == 0) gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ return error;}struct inode *gfs2_lookup_simple(struct inode *dip, const char *name){ struct qstr qstr; struct inode *inode; gfs2_str2qstr(&qstr, name); inode = gfs2_lookupi(dip, &qstr, 1, NULL); /* gfs2_lookupi has inconsistent callers: vfs * related routines expect NULL for no entry found, * gfs2_lookup_simple callers expect ENOENT * and do not check for NULL. */ if (inode == NULL) return ERR_PTR(-ENOENT); else return inode;}/** * gfs2_lookupi - Look up a filename in a directory and return its inode * @d_gh: An initialized holder for the directory glock * @name: The name of the inode to look for * @is_root: If 1, ignore the caller's permissions * @i_gh: An uninitialized holder for the new inode glock * * 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 */struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root, struct nameidata *nd){ struct super_block *sb = dir->i_sb; struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_holder d_gh; int error = 0; struct inode *inode = NULL; int unlock = 0; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -