From: Hugh Dickins Remove the duplicated checks in shmem_file-write(), use generic_write_checks() instead. mm/shmem.c | 97 ++++++++++--------------------------------------------------- 1 files changed, 17 insertions(+), 80 deletions(-) diff -puN mm/shmem.c~tmpfs-1-use-generic_write_checks mm/shmem.c --- 25/mm/shmem.c~tmpfs-1-use-generic_write_checks 2003-04-02 22:51:04.000000000 -0800 +++ 25-akpm/mm/shmem.c 2003-04-02 22:51:04.000000000 -0800 @@ -1126,10 +1126,8 @@ static ssize_t shmem_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; loff_t pos; unsigned long written; - long status; int err; loff_t maxpos; @@ -1142,88 +1140,25 @@ shmem_file_write(struct file *file, cons down(&inode->i_sem); pos = *ppos; - err = -EINVAL; - if (pos < 0) - goto out_nc; - - err = file->f_error; - if (err) { - file->f_error = 0; - goto out_nc; - } - written = 0; - if (file->f_flags & O_APPEND) - pos = inode->i_size; + err = generic_write_checks(inode, file, &pos, &count, 0); + if (err || !count) + goto out; maxpos = inode->i_size; - if (pos + count > inode->i_size) { + if (maxpos < pos + count) { maxpos = pos + count; - if (maxpos > SHMEM_MAX_BYTES) - maxpos = SHMEM_MAX_BYTES; if (!vm_enough_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size))) { err = -ENOMEM; - goto out_nc; - } - } - - /* - * Check whether we've reached the file size limit. - */ - err = -EFBIG; - if (limit != RLIM_INFINITY) { - if (pos >= limit) { - send_sig(SIGXFSZ, current, 0); - goto out; - } - if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) { - /* send_sig(SIGXFSZ, current, 0); */ - count = limit - (u32)pos; - } - } - - /* - * LFS rule - */ - if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { - if (pos >= MAX_NON_LFS) { - send_sig(SIGXFSZ, current, 0); goto out; } - if (count > MAX_NON_LFS - (u32)pos) { - /* send_sig(SIGXFSZ, current, 0); */ - count = MAX_NON_LFS - (u32)pos; - } } - /* - * Are we about to exceed the fs block limit ? - * - * If we have written data it becomes a short write - * If we have exceeded without writing data we send - * a signal and give them an EFBIG. - * - * Linus frestrict idea will clean these up nicely.. - */ - if (pos >= SHMEM_MAX_BYTES) { - if (count || pos > SHMEM_MAX_BYTES) { - send_sig(SIGXFSZ, current, 0); - err = -EFBIG; - goto out; - } - /* zero-length writes at ->s_maxbytes are OK */ - } - if (pos + count > SHMEM_MAX_BYTES) - count = SHMEM_MAX_BYTES - pos; + remove_suid(file->f_dentry); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; - status = 0; - if (count) { - remove_suid(file->f_dentry); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - } - - while (count) { + do { struct page *page = NULL; unsigned long bytes, index, offset; char *kaddr; @@ -1241,8 +1176,8 @@ shmem_file_write(struct file *file, cons * But it still may be a good idea to prefault below. */ - status = shmem_getpage(inode, index, &page, SGP_WRITE); - if (status) + err = shmem_getpage(inode, index, &page, SGP_WRITE); + if (err) break; left = bytes; @@ -1263,7 +1198,7 @@ shmem_file_write(struct file *file, cons flush_dcache_page(page); if (left) { page_cache_release(page); - status = -EFAULT; + err = -EFAULT; break; } @@ -1271,7 +1206,8 @@ shmem_file_write(struct file *file, cons page_cache_release(page); /* - * Balance dirty pages?? + * Our dirty pages are not counted in nr_dirty, + * and we do not attempt to balance dirty pages. */ written += bytes; @@ -1280,15 +1216,16 @@ shmem_file_write(struct file *file, cons buf += bytes; if (pos > inode->i_size) inode->i_size = pos; - } + } while (count); *ppos = pos; - err = written ? written : status; -out: + if (written) + err = written; + /* Short writes give back address space */ if (inode->i_size != maxpos) vm_unacct_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size)); -out_nc: +out: up(&inode->i_sem); return err; } _