[PATCH] tmpfs 6/9 shmem_file_write update

Hugh Dickins (hugh@veritas.com)
Fri, 18 Oct 2002 00:56:55 +0100 (BST)


Checked shmem_file_write against recent filemap source, and against
2.4 and 2.4-ac: folded in missing fixes, mostly related to far file
positions. Plus the new kmap_atomic copying technique. But for now,
as before, no mark_page_accessed or SetPageReferenced in shmem.c: add
those, or whatever, later on when akpm has reviewed usage elsewhere.

--- tmpfs5/mm/shmem.c Thu Oct 17 22:01:29 2002
+++ tmpfs6/mm/shmem.c Thu Oct 17 22:01:39 2002
@@ -1062,12 +1062,46 @@
send_sig(SIGXFSZ, current, 0);
goto out;
}
- if (count > limit - pos) {
+ 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);
- count = limit - pos;
+ 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;
+
status = 0;
if (count) {
remove_suid(file->f_dentry);
@@ -1077,51 +1111,62 @@
while (count) {
unsigned long bytes, index, offset;
char *kaddr;
+ int left;

- /*
- * Try to find the page in the cache. If it isn't there,
- * allocate a free page.
- */
offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
index = pos >> PAGE_CACHE_SHIFT;
bytes = PAGE_CACHE_SIZE - offset;
- if (bytes > count) {
+ if (bytes > count)
bytes = count;
- }

/*
* We don't hold page lock across copy from user -
* what would it guard against? - so no deadlock here.
+ * But it still may be a good idea to prefault below.
*/

status = shmem_getpage(inode, index, &page, SGP_WRITE);
if (status)
break;

- kaddr = kmap(page);
- status = __copy_from_user(kaddr+offset, buf, bytes);
- kunmap(page);
- if (status)
- goto fail_write;
-
+ left = bytes;
+ if (PageHighMem(page)) {
+ volatile unsigned char dummy;
+ __get_user(dummy, buf);
+ __get_user(dummy, buf + bytes - 1);
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ left = __copy_from_user(kaddr + offset, buf, bytes);
+ kunmap_atomic(kaddr, KM_USER0);
+ }
+ if (left) {
+ kaddr = kmap(page);
+ left = __copy_from_user(kaddr + offset, buf, bytes);
+ kunmap(page);
+ }
flush_dcache_page(page);
- if (bytes > 0) {
- set_page_dirty(page);
- written += bytes;
- count -= bytes;
- pos += bytes;
- buf += bytes;
- if (pos > inode->i_size)
- inode->i_size = pos;
+ if (left) {
+ page_cache_release(page);
+ status = -EFAULT;
+ break;
}
-release:
+
+ set_page_dirty(page);
page_cache_release(page);

- if (status < 0)
- break;
+ /*
+ * Balance dirty pages??
+ */
+
+ written += bytes;
+ count -= bytes;
+ pos += bytes;
+ buf += bytes;
+ if (pos > inode->i_size)
+ inode->i_size = pos;
}
- *ppos = pos;

+ *ppos = pos;
err = written ? written : status;
out:
/* Short writes give back address space */
@@ -1130,10 +1175,6 @@
out_nc:
up(&inode->i_sem);
return err;
-fail_write:
- status = -EFAULT;
- ClearPageUptodate(page);
- goto release;
}

static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
@@ -1407,9 +1448,9 @@
spin_lock(&shmem_ilock);
list_add_tail(&info->list, &shmem_inodes);
spin_unlock(&shmem_ilock);
- kaddr = kmap(page);
+ kaddr = kmap_atomic(page, KM_USER0);
memcpy(kaddr, symname, len);
- kunmap(page);
+ kunmap_atomic(kaddr, KM_USER0);
set_page_dirty(page);
page_cache_release(page);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/