📄 namei.c
字号:
* anyway. */ if ((p_blocks << sb->s_blocksize_bits) < bytes_left) { status = -EIO; mlog_errno(status); goto bail; } virtual = 0; while(bytes_left > 0) { c = &symname[virtual * sb->s_blocksize]; bhs[virtual] = sb_getblk(sb, p_blkno); if (!bhs[virtual]) { status = -ENOMEM; mlog_errno(status); goto bail; } ocfs2_set_new_buffer_uptodate(inode, bhs[virtual]); status = ocfs2_journal_access(handle, inode, bhs[virtual], OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } memset(bhs[virtual]->b_data, 0, sb->s_blocksize); memcpy(bhs[virtual]->b_data, c, (bytes_left > sb->s_blocksize) ? sb->s_blocksize : bytes_left); status = ocfs2_journal_dirty(handle, bhs[virtual]); if (status < 0) { mlog_errno(status); goto bail; } virtual++; p_blkno++; bytes_left -= sb->s_blocksize; } status = 0;bail: if (bhs) { for(i = 0; i < blocks; i++) if (bhs[i]) brelse(bhs[i]); kfree(bhs); } mlog_exit(status); return status;}static int ocfs2_symlink(struct inode *dir, struct dentry *dentry, const char *symname){ int status, l, credits; u64 newsize; struct ocfs2_super *osb = NULL; struct inode *inode = NULL; struct super_block *sb; struct buffer_head *new_fe_bh = NULL; struct buffer_head *de_bh = NULL; struct buffer_head *parent_fe_bh = NULL; struct ocfs2_dinode *fe = NULL; struct ocfs2_dinode *dirfe; handle_t *handle = NULL; struct ocfs2_alloc_context *inode_ac = NULL; struct ocfs2_alloc_context *data_ac = NULL; mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir, dentry, symname, dentry->d_name.len, dentry->d_name.name); sb = dir->i_sb; osb = OCFS2_SB(sb); l = strlen(symname) + 1; credits = ocfs2_calc_symlink_credits(sb); /* lock the parent directory */ status = ocfs2_inode_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); return status; } 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 bail; } status = ocfs2_check_dir_for_entry(dir, dentry->d_name.name, dentry->d_name.len); if (status) goto bail; 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 bail; } status = ocfs2_reserve_new_inode(osb, &inode_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } /* don't reserve bitmap space for fast symlinks. */ if (l > ocfs2_fast_symlink_chars(sb)) { status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } } handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto bail; } status = ocfs2_mknod_locked(osb, dir, dentry, S_IFLNK | S_IRWXUGO, 0, &new_fe_bh, parent_fe_bh, handle, &inode, inode_ac); if (status < 0) { mlog_errno(status); goto bail; } fe = (struct ocfs2_dinode *) new_fe_bh->b_data; inode->i_rdev = 0; newsize = l - 1; if (l > ocfs2_fast_symlink_chars(sb)) { u32 offset = 0; inode->i_op = &ocfs2_symlink_inode_operations; status = ocfs2_do_extend_allocation(osb, inode, &offset, 1, 0, new_fe_bh, handle, data_ac, NULL, NULL); if (status < 0) { if (status != -ENOSPC && status != -EINTR) { mlog(ML_ERROR, "Failed to extend file to %llu\n", (unsigned long long)newsize); mlog_errno(status); status = -ENOSPC; } goto bail; } i_size_write(inode, newsize); inode->i_blocks = ocfs2_inode_sector_count(inode); } else { inode->i_op = &ocfs2_fast_symlink_inode_operations; memcpy((char *) fe->id2.i_symlink, symname, l); i_size_write(inode, newsize); inode->i_blocks = 0; } status = ocfs2_mark_inode_dirty(handle, inode, new_fe_bh); if (status < 0) { mlog_errno(status); goto bail; } if (!ocfs2_inode_is_fast_symlink(inode)) { status = ocfs2_create_symlink_data(osb, handle, inode, symname); if (status < 0) { mlog_errno(status); goto bail; } } status = ocfs2_add_entry(handle, dentry, inode, le64_to_cpu(fe->i_blkno), parent_fe_bh, de_bh); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno); if (status) { mlog_errno(status); goto bail; } insert_inode_hash(inode); dentry->d_op = &ocfs2_dentry_ops; d_instantiate(dentry, inode);bail: if (handle) ocfs2_commit_trans(osb, handle); ocfs2_inode_unlock(dir, 1); if (new_fe_bh) brelse(new_fe_bh); if (parent_fe_bh) brelse(parent_fe_bh); if (de_bh) brelse(de_bh); if (inode_ac) ocfs2_free_alloc_context(inode_ac); if (data_ac) ocfs2_free_alloc_context(data_ac); if ((status < 0) && inode) iput(inode); mlog_exit(status); return status;}static int ocfs2_blkno_stringify(u64 blkno, char *name){ int status, namelen; mlog_entry_void(); namelen = snprintf(name, OCFS2_ORPHAN_NAMELEN + 1, "%016llx", (long long)blkno); if (namelen <= 0) { if (namelen) status = namelen; else status = -EINVAL; mlog_errno(status); goto bail; } if (namelen != OCFS2_ORPHAN_NAMELEN) { status = -EINVAL; mlog_errno(status); goto bail; } mlog(0, "built filename '%s' for orphan dir (len=%d)\n", name, namelen); status = 0;bail: mlog_exit(status); return status;}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){ struct inode *orphan_dir_inode; struct buffer_head *orphan_dir_bh = NULL; int status = 0; status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name); if (status < 0) { mlog_errno(status); return status; } orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, osb->slot_num); if (!orphan_dir_inode) { status = -ENOENT; mlog_errno(status); return status; } mutex_lock(&orphan_dir_inode->i_mutex); status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode, orphan_dir_bh, name, OCFS2_ORPHAN_NAMELEN, de_bh); if (status < 0) { ocfs2_inode_unlock(orphan_dir_inode, 1); mlog_errno(status); goto leave; } *ret_orphan_dir = orphan_dir_inode;leave: if (status) { mutex_unlock(&orphan_dir_inode->i_mutex); iput(orphan_dir_inode); } if (orphan_dir_bh) brelse(orphan_dir_bh); mlog_exit(status); return status;}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){ struct buffer_head *orphan_dir_bh = NULL; int status = 0; struct ocfs2_dinode *orphan_fe; mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); status = ocfs2_read_block(osb, OCFS2_I(orphan_dir_inode)->ip_blkno, &orphan_dir_bh, OCFS2_BH_CACHED, orphan_dir_inode); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_journal_access(handle, orphan_dir_inode, orphan_dir_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } /* we're a cluster, and nlink can change on disk from * underneath us... */ orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data; if (S_ISDIR(inode->i_mode)) le16_add_cpu(&orphan_fe->i_links_count, 1); orphan_dir_inode->i_nlink = le16_to_cpu(orphan_fe->i_links_count); status = ocfs2_journal_dirty(handle, orphan_dir_bh); if (status < 0) { mlog_errno(status); goto leave; } status = __ocfs2_add_entry(handle, orphan_dir_inode, name, OCFS2_ORPHAN_NAMELEN, inode, OCFS2_I(inode)->ip_blkno, orphan_dir_bh, de_bh); if (status < 0) { mlog_errno(status); goto leave; } le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL); /* Record which orphan dir our inode now resides * in. delete_inode will use this to determine which orphan * dir to lock. */ fe->i_orphaned_slot = cpu_to_le16(osb->slot_num); mlog(0, "Inode %llu orphaned in slot %d\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);leave: if (orphan_dir_bh) brelse(orphan_dir_bh); mlog_exit(status); return status;}/* unlike orphan_add, we expect the orphan dir to already be locked here. */int ocfs2_orphan_del(struct ocfs2_super *osb, handle_t *handle, struct inode *orphan_dir_inode, struct inode *inode, struct buffer_head *orphan_dir_bh){ char name[OCFS2_ORPHAN_NAMELEN + 1]; struct ocfs2_dinode *orphan_fe; int status = 0; struct buffer_head *target_de_bh = NULL; struct ocfs2_dir_entry *target_de = NULL; mlog_entry_void(); status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name); if (status < 0) { mlog_errno(status); goto leave; } mlog(0, "removing '%s' from orphan dir %llu (namelen=%d)\n", name, (unsigned long long)OCFS2_I(orphan_dir_inode)->ip_blkno, OCFS2_ORPHAN_NAMELEN); /* find it's spot in the orphan directory */ target_de_bh = ocfs2_find_entry(name, OCFS2_ORPHAN_NAMELEN, orphan_dir_inode, &target_de); if (!target_de_bh) { status = -ENOENT; mlog_errno(status); goto leave; } /* remove it from the orphan directory */ status = ocfs2_delete_entry(handle, orphan_dir_inode, target_de, target_de_bh); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_journal_access(handle,orphan_dir_inode, orphan_dir_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } /* do the i_nlink dance! :) */ orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data; if (S_ISDIR(inode->i_mode)) le16_add_cpu(&orphan_fe->i_links_count, -1); orphan_dir_inode->i_nlink = le16_to_cpu(orphan_fe->i_links_count); status = ocfs2_journal_dirty(handle, orphan_dir_bh); if (status < 0) { mlog_errno(status); goto leave; }leave: if (target_de_bh) brelse(target_de_bh); mlog_exit(status); return status;}#ifdef IOP_IS_NOT_CONSTstruct inode_operations ocfs2_dir_iops = {#elseconst struct inode_operations ocfs2_dir_iops = {#endif .create = ocfs2_create, .lookup = ocfs2_lookup, .link = ocfs2_link, .unlink = ocfs2_unlink, .rmdir = ocfs2_unlink, .symlink = ocfs2_symlink, .mkdir = ocfs2_mkdir, .mknod = ocfs2_mknod, .rename = ocfs2_rename, .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -