📄 namei.c
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * namei.c * * Create and rename file, directory, symlinks * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * Portions of this code from linux/fs/ext3/dir.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/fs/minix/dir.c * * Copyright (C) 1991, 1992 Linux Torvalds * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */#include <linux/fs.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#define MLOG_MASK_PREFIX ML_NAMEI#include <cluster/masklog.h>#include "ocfs2.h"#include "alloc.h"#include "dcache.h"#include "dir.h"#include "dlmglue.h"#include "extent_map.h"#include "file.h"#include "inode.h"#include "journal.h"#include "namei.h"#include "suballoc.h"#include "super.h"#include "symlink.h"#include "sysfile.h"#include "uptodate.h"#include "buffer_head_io.h"static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode *dir, struct dentry *dentry, int mode, dev_t dev, struct buffer_head **new_fe_bh, struct buffer_head *parent_fe_bh, handle_t *handle, struct inode **ret_inode, struct ocfs2_alloc_context *inode_ac);static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, struct inode **ret_orphan_dir, struct inode *inode, char *name, struct buffer_head **de_bh);static int ocfs2_orphan_add(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, struct ocfs2_dinode *fe, char *name, struct buffer_head *de_bh, struct inode *orphan_dir_inode);static int ocfs2_create_symlink_data(struct ocfs2_super *osb, handle_t *handle, struct inode *inode, const char *symname);/* An orphan dir name is an 8 byte value, printed as a hex string */#define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ int status; u64 blkno; struct inode *inode = NULL; struct dentry *ret; struct ocfs2_inode_info *oi; mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry, dentry->d_name.len, dentry->d_name.name); if (dentry->d_name.len > OCFS2_MAX_FILENAME_LEN) { ret = ERR_PTR(-ENAMETOOLONG); goto bail; } mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); status = ocfs2_inode_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); ret = ERR_PTR(status); goto bail; } status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name, dentry->d_name.len, &blkno); if (status < 0) goto bail_add; inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0); if (IS_ERR(inode)) { ret = ERR_PTR(-EACCES); goto bail_unlock; } oi = OCFS2_I(inode); /* Clear any orphaned state... If we were able to look up the * inode from a directory, it certainly can't be orphaned. We * might have the bad state from a node which intended to * orphan this inode but crashed before it could commit the * unlink. */ spin_lock(&oi->ip_lock); oi->ip_flags &= ~OCFS2_INODE_MAYBE_ORPHANED; spin_unlock(&oi->ip_lock);bail_add: dentry->d_op = &ocfs2_dentry_ops; ret = d_splice_alias(inode, dentry); if (inode) { /* * If d_splice_alias() finds a DCACHE_DISCONNECTED * dentry, it will d_move() it on top of ourse. The * return value will indicate this however, so in * those cases, we switch them around for the locking * code. * * NOTE: This dentry already has ->d_op set from * ocfs2_get_parent() and ocfs2_get_dentry() */ if (ret) dentry = ret; status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno); if (status) { mlog_errno(status); ret = ERR_PTR(status); goto bail_unlock; } }bail_unlock: /* Don't drop the cluster lock until *after* the d_add -- * unlink on another node will message us to remove that * dentry under this lock so otherwise we can race this with * the downconvert thread and have a stale dentry. */ ocfs2_inode_unlock(dir, 0);bail: mlog_exit_ptr(ret); return ret;}static int ocfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev){ int status = 0; struct buffer_head *parent_fe_bh = NULL; handle_t *handle = NULL; struct ocfs2_super *osb; struct ocfs2_dinode *dirfe; struct buffer_head *new_fe_bh = NULL; struct buffer_head *de_bh = NULL; struct inode *inode = NULL; struct ocfs2_alloc_context *inode_ac = NULL; struct ocfs2_alloc_context *data_ac = NULL; mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, (unsigned long)dev, dentry->d_name.len, dentry->d_name.name); /* get our super block */ osb = OCFS2_SB(dir->i_sb); status = ocfs2_inode_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); return status; } if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) { status = -EMLINK; goto leave; } dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data; if (!dirfe->i_links_count) { /* can't make a file in a deleted directory. */ status = -ENOENT; goto leave; } status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name, dentry->d_name.len); if (status) goto leave; /* get a spot inside the dir. */ status = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh, dentry->d_name.name, dentry->d_name.len, &de_bh); if (status < 0) { mlog_errno(status); goto leave; } /* reserve an inode spot */ status = ocfs2_reserve_new_inode(osb, &inode_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } /* Reserve a cluster if creating an extent based directory. */ if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } } handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto leave; } /* do the real work now. */ status = ocfs2_mknod_locked(osb, dir, dentry, mode, dev, &new_fe_bh, parent_fe_bh, handle, &inode, inode_ac); if (status < 0) { mlog_errno(status); goto leave; } if (S_ISDIR(mode)) { status = ocfs2_fill_new_dir(osb, handle, dir, inode, new_fe_bh, data_ac); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_journal_access(handle, dir, parent_fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } le16_add_cpu(&dirfe->i_links_count, 1); status = ocfs2_journal_dirty(handle, parent_fe_bh); if (status < 0) { mlog_errno(status); goto leave; } inc_nlink(dir); } status = ocfs2_add_entry(handle, dentry, inode, OCFS2_I(inode)->ip_blkno, parent_fe_bh, de_bh); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno); if (status) { mlog_errno(status); goto leave; } insert_inode_hash(inode); dentry->d_op = &ocfs2_dentry_ops; d_instantiate(dentry, inode); status = 0;leave: if (handle) ocfs2_commit_trans(osb, handle); ocfs2_inode_unlock(dir, 1); if (status == -ENOSPC) mlog(0, "Disk is full\n"); if (new_fe_bh) brelse(new_fe_bh); if (de_bh) brelse(de_bh); if (parent_fe_bh) brelse(parent_fe_bh); if ((status < 0) && inode) iput(inode); if (inode_ac) ocfs2_free_alloc_context(inode_ac); if (data_ac) ocfs2_free_alloc_context(data_ac); mlog_exit(status); return status;}static int ocfs2_mknod_locked(struct ocfs2_super *osb, struct inode *dir, struct dentry *dentry, int mode, dev_t dev, struct buffer_head **new_fe_bh, struct buffer_head *parent_fe_bh, handle_t *handle, struct inode **ret_inode, struct ocfs2_alloc_context *inode_ac){ int status = 0; struct ocfs2_dinode *fe = NULL; struct ocfs2_extent_list *fel; u64 fe_blkno = 0; u16 suballoc_bit; struct inode *inode = NULL; mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, (unsigned long)dev, dentry->d_name.len, dentry->d_name.name); *new_fe_bh = NULL; *ret_inode = NULL; status = ocfs2_claim_new_inode(osb, handle, inode_ac, &suballoc_bit, &fe_blkno); if (status < 0) { mlog_errno(status); goto leave; } inode = new_inode(dir->i_sb); if (IS_ERR(inode)) { status = PTR_ERR(inode); mlog(ML_ERROR, "new_inode failed!\n"); goto leave; } /* populate as many fields early on as possible - many of * these are used by the support functions here and in * callers. */ inode->i_ino = ino_from_blkno(osb->sb, fe_blkno); OCFS2_I(inode)->ip_blkno = fe_blkno; if (S_ISDIR(mode)) inode->i_nlink = 2; else inode->i_nlink = 1; inode->i_mode = mode; spin_lock(&osb->osb_lock); inode->i_generation = osb->s_next_generation++; spin_unlock(&osb->osb_lock); *new_fe_bh = sb_getblk(osb->sb, fe_blkno); if (!*new_fe_bh) { status = -EIO; mlog_errno(status); goto leave; } ocfs2_set_new_buffer_uptodate(inode, *new_fe_bh); status = ocfs2_journal_access(handle, inode, *new_fe_bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto leave; } fe = (struct ocfs2_dinode *) (*new_fe_bh)->b_data; memset(fe, 0, osb->sb->s_blocksize); fe->i_generation = cpu_to_le32(inode->i_generation); fe->i_fs_generation = cpu_to_le32(osb->fs_generation); fe->i_blkno = cpu_to_le64(fe_blkno); fe->i_suballoc_bit = cpu_to_le16(suballoc_bit); fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot); fe->i_uid = cpu_to_le32(current->fsuid); if (dir->i_mode & S_ISGID) { fe->i_gid = cpu_to_le32(dir->i_gid); if (S_ISDIR(mode)) mode |= S_ISGID; } else fe->i_gid = cpu_to_le32(current->fsgid); fe->i_mode = cpu_to_le16(mode); if (S_ISCHR(mode) || S_ISBLK(mode)) fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev)); fe->i_links_count = cpu_to_le16(inode->i_nlink); fe->i_last_eb_blk = 0; strcpy(fe->i_signature, OCFS2_INODE_SIGNATURE); le32_add_cpu(&fe->i_flags, OCFS2_VALID_FL); fe->i_atime = fe->i_ctime = fe->i_mtime = cpu_to_le64(CURRENT_TIME.tv_sec); fe->i_mtime_nsec = fe->i_ctime_nsec = fe->i_atime_nsec = cpu_to_le32(CURRENT_TIME.tv_nsec); fe->i_dtime = 0; /* * If supported, directories start with inline data. */ if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) { u16 feat = le16_to_cpu(fe->i_dyn_features); fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb)); } else { fel = &fe->id2.i_list; fel->l_tree_depth = 0; fel->l_next_free_rec = 0; fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb)); } status = ocfs2_journal_dirty(handle, *new_fe_bh); if (status < 0) { mlog_errno(status); goto leave; } if (ocfs2_populate_inode(inode, fe, 1) < 0) { mlog(ML_ERROR, "populate inode failed! bh->b_blocknr=%llu, " "i_blkno=%llu, i_ino=%lu\n", (unsigned long long)(*new_fe_bh)->b_blocknr, (unsigned long long)le64_to_cpu(fe->i_blkno), inode->i_ino); BUG(); } ocfs2_inode_set_new(osb, inode); if (!ocfs2_mount_local(osb)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -