📄 file.c
字号:
/* * FILE NAME fs/pramfs/file.c * * BRIEF DESCRIPTION * * File operations for files. * * Author: Steve Longerbeam <stevel@mvista.com, or source@mvista.com> * * Copyright 2003 Sony Corporation * Copyright 2003 Matsushita Electric Industrial Co., Ltd. * 2003-2004 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */#include <linux/fs.h>#include <linux/pram_fs.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/uio.h>#include <asm/uaccess.h>static int pram_open_file(struct inode * inode, struct file * filp){ filp->f_flags |= O_DIRECT; return generic_file_open(inode, filp);}/* * Called when an inode is released. Note that this is different * from pram_open_file: open gets called at every open, but release * gets called only when /all/ the files are closed. */static int pram_release_file (struct inode * inode, struct file * filp){ return 0;}#if defined(CONFIG_PRAMFS_VNVRAM) && defined(CONFIG_PRAMFS_FAILSAFE)static inline int pram_is_alloc_blocks(struct inode * inode, int file_blocknr, int num){ struct super_block * sb = inode->i_sb; struct pram_inode * pi = pram_get_inode(sb, inode->i_ino); int N = sb->s_blocksize >> 2; // num block ptrs per block int Nbits = sb->s_blocksize_bits - 2; int first_file_blocknr; int last_file_blocknr; int first_row_index, last_row_index; int i; pram_off_t * row; if (!pi->i_type.reg.row_block) return 1; row = pram_get_block(sb, pi->i_type.reg.row_block); first_file_blocknr = (file_blocknr > inode->i_blocks) ? inode->i_blocks : file_blocknr; last_file_blocknr = file_blocknr + num - 1; first_row_index = first_file_blocknr >> Nbits; last_row_index = last_file_blocknr >> Nbits; if (last_row_index >= N || first_row_index >= N) return -ENOSPC; for (i = first_row_index; i <= last_row_index; i++) { int first_col_index, last_col_index, j; pram_off_t * col; /* * we are starting a new row, so make sure * there is a block allocated for the row. */ if (!row[i]) return 1; col = pram_get_block(sb, row[i]); first_col_index = (i == first_row_index) ? first_file_blocknr & (N-1) : 0; last_col_index = (i == last_row_index) ? last_file_blocknr & (N-1) : N-1; for (j = first_col_index; j <= last_col_index; j++) { if (!col[j]) return 1; } } return 0;}#else#define pram_is_alloc_blocks(inode, file_blocknr, num) (1)#endifint pram_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs){ struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct super_block * sb = inode->i_sb; int progress = 0, retval = 0; struct pram_inode * pi; void * tmp = NULL; unsigned long blocknr, blockoff; int num_blocks, blocksize_mask, blocksize, blocksize_bits; char __user *buf = iov->iov_base; size_t length = iov->iov_len; int failsafe_locked = 0; if (length < 0) return -EINVAL; if ((rw == READ) && (offset + length > inode->i_size)) length = inode->i_size - offset; if (!length) goto out; blocksize_bits = inode->i_sb->s_blocksize_bits; blocksize = 1 << blocksize_bits; blocksize_mask = blocksize - 1; /* find starting block number to access */ blocknr = offset >> blocksize_bits; /* find starting offset within starting block */ blockoff = offset & blocksize_mask; /* find number of blocks to access */ num_blocks = (blockoff + length + blocksize_mask) >> blocksize_bits; if (rw == WRITE) { // prepare a temporary buffer to hold a user data block // for writing. tmp = kmalloc(blocksize, GFP_KERNEL); if (!tmp) return -ENOMEM; retval = pram_is_alloc_blocks(inode, blocknr, num_blocks); if (retval > 0) { pram_lock_failsafe(sb, PRAM_FAILSAFE_OP_ALLOC_BLOCKS, inode->i_ino, (u32)offset, length); /* now allocate the data blocks we'll need */ retval = pram_alloc_blocks(inode, blocknr, num_blocks); pram_unlock_failsafe(sb); if (retval) goto fail; } else if (retval < 0) goto fail; } pi = pram_get_inode(inode->i_sb, inode->i_ino); while (length) { int count; pram_off_t block = pram_find_data_block(inode, blocknr++); u8* bp = (u8*)pram_get_block(sb, block); if (!bp) goto fail; count = blockoff + length > blocksize ? blocksize - blockoff : length; if (rw == READ) { retval = copy_to_user(buf, &bp[blockoff], count); if (retval) break; /* goto fail? */ } else { retval = copy_from_user(tmp, buf, count); if (retval) break; /* goto fail? */ if (sb->s_flags & MS_DATA_FAILSAFE) { pram_lock_failsafe(sb, PRAM_FAILSAFE_OP_DIRECT_IO, inode->i_ino, block, 0); pram_backup_add_block(inode->i_sb, bp); } pram_lock_block(inode->i_sb, bp); memcpy(&bp[blockoff], tmp, count); pram_unlock_block(inode->i_sb, bp); if (sb->s_flags & MS_DATA_FAILSAFE) { pram_backup_del_block(inode->i_sb, bp); pram_unlock_failsafe(sb); } } progress += count; buf += count; length -= count; blockoff = 0; } retval = progress; fail: if (failsafe_locked) pram_unlock_failsafe(sb); if (tmp) kfree(tmp); out: return retval;}const struct file_operations pram_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .aio_read = generic_file_aio_read, .write = do_sync_write, .aio_write = generic_file_aio_write, .ioctl = pram_ioctl, .mmap = generic_file_mmap, .open = pram_open_file, .release = pram_release_file, .fsync = pram_sync_file, .splice_read = generic_file_splice_read,};const struct inode_operations pram_file_inode_operations = { .truncate = pram_truncate,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -