Re: falloc and related stuff

2015-04-09 Thread kanonenvogel....@gmail.com
Struct file again.

f_flag isn’t modified often, so it’s modifacation can be atomic.
f_msgcount and f_rxfer, f_wxfer, f_seek, f_rbytes, f_wbytes can be protected by 
rwlock. 
f_offset protection is actual for vnodes only.
FIF_MARK and FIF_DEFER flags are used only by unpc garbage collector. This 
flags can
be moved out from f_iflags, for example to f_unpc_flags, and use their own 
protection.
FIF_HASLOCK checked only in vn_closefile(), but this flag doesn’t indicate 
actual vnode lock
state, because VOP_ADVLOCK()’s return value is not checked. May be it can be 
replaced by
 new vn_islocked() function, which will check actual vnode lock possibility and 
lock state?
only FIF_LARVAL remains in f_iflags, this flag sets only once, so it’s 
modification can be atomic.
f_count may be modified and checked under rwlock, but I think atomic ops are 
better on smp,
afaik, with uniprocessor kernel simple increment/decrement over volatile 
variable will be enough.

This modification doesn’t break pstat, all related FIF_* flags can be set in 
kinfo_file struct.  

f_offset protection can be done like in patch below. it is just 
proof-of-concept. I think f_offset 
protection stuff can be moved to external struct, which will be stored in hash 
with fp address as key.

FIF_MARK and FIF_DEFER stuff can be moved to external struct too, I suppose.

Index: compat/common/compat_dir.c
===
RCS file: /cvs/src/sys/compat/common/compat_dir.c,v
retrieving revision 1.11
diff -u -p -r1.11 compat_dir.c
--- compat/common/compat_dir.c  16 Dec 2014 21:25:28 -  1.11
+++ compat/common/compat_dir.c  9 Apr 2015 10:40:55 -
@@ -51,7 +51,6 @@ readdir_with_callback(struct file *fp, o
struct iovec aiov;
int eofflag = 0;
int error, len, reclen;
-   off_t newoff = *off;
struct vnode *vp;
struct vattr va;

@@ -84,10 +83,16 @@ again:
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_procp = curproc;
auio.uio_resid = buflen;
-   auio.uio_offset = newoff;
-
+   if (fp-f_offset == off)
+   foffset_lock(fp, auio.uio_offset);
+   else
+   auio.uio_offset = *off;
error = VOP_READDIR(vp, auio, fp-f_cred, eofflag);
-   *off = auio.uio_offset;
+   if (fp-f_offset == off)
+   foffset_unlock(fp, auio.uio_offset);
+   else
+   *off = auio.uio_offset;
+
if (error)
goto out;
 
Index: kern/kern_descrip.c
===
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.116
diff -u -p -r1.116 kern_descrip.c
--- kern/kern_descrip.c 19 Jan 2015 01:19:17 -  1.116
+++ kern/kern_descrip.c 9 Apr 2015 10:41:10 -
@@ -61,6 +61,7 @@
 #include sys/event.h
 #include sys/pool.h
 #include sys/ktrace.h
+#include sys/rwlock.h
 
 #include sys/pipe.h
 
@@ -451,9 +452,9 @@ restart:
if (fl.l_start == 0  fl.l_len  0) {
/* lockf(3) compliance hack */
fl.l_len = -fl.l_len;
-   fl.l_start = fp-f_offset - fl.l_len;
+   fl.l_start = foffset_get(fp) - fl.l_len;
} else
-   fl.l_start += fp-f_offset;
+   fl.l_start += foffset_get(fp);
}
switch (fl.l_type) {
 
@@ -514,9 +515,9 @@ restart:
if (fl.l_start == 0  fl.l_len  0) {
/* lockf(3) compliance hack */
fl.l_len = -fl.l_len;
-   fl.l_start = fp-f_offset - fl.l_len;
+   fl.l_start = foffset_get(fp) - fl.l_len;
} else
-   fl.l_start += fp-f_offset;
+   fl.l_start += foffset_get(fp);
}
if (fl.l_type != F_RDLCK 
fl.l_type != F_WRLCK 
@@ -869,6 +870,7 @@ restart:
 */
nfiles++;
fp = pool_get(file_pool, PR_WAITOK|PR_ZERO);
+   rw_init(fp-f_offset_lck, f_offset_lck);
fp-f_iflags = FIF_LARVAL;
if ((fq = p-p_fd-fd_ofiles[0]) != NULL) {
LIST_INSERT_AFTER(fq, fp, f_list);
@@ -1125,6 +1127,47 @@ fdrop(struct file *fp, struct proc *p)
pool_put(file_pool, fp);
 
return (error);
+}
+
+off_t
+foffset_get(struct file *fp)
+{
+   off_t offset;
+
+   rw_enter_read(fp-f_offset_lck);
+   offset = fp-f_offset;
+   rw_exit_read(fp-f_offset_lck);
+   
+   return offset;
+}
+
+void
+foffset_lock(struct file *fp, off_t *foffset)
+{
+   KASSERT(foffset != NULL);
+   rw_enter_write(fp-f_offset_lck);
+   while (fp-f_offset_lckf  FOFFSET_LOCKED) {
+   fp-f_offset_lckf |= FOFFSET_LOCK_WAITING;
+   

Re: falloc and related stuff

2015-04-08 Thread kanonenvogel....@gmail.com

On 08 Apr 2015, at 02:31, Philip Guenther guent...@gmail.com wrote:

 On Tue, Apr 7, 2015 at 3:57 PM, Kanonenvogel kanonenvogel@gmail.com 
 wrote:
 I have idea to modify falloc() function and related logic.
 Now, after successful faclloc call,  we have half-initialized struct file 
 object, protected by FIF_LARVAL flag.
 I want to initialise struct file object within falloc() and then put it to 
 fd_ofiles array and filehead list. This modification
 permits to avoid half-initialization state and remove FIF_LARVAL flag and 
 related logic.
 
 The hard case is blocking opens of fifos, as the underlying operation
 involves a change visible to another process and that therefore cannot
 be rolled back.
 
 
 Philip Guenther
Ok, I understood.
And what about make struct file more smp friendly? For example, make operations 
under
f_iflags and f_flags atomic?

Index: kern/kern_descrip.c
===
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.116
diff -u -p -r1.116 kern_descrip.c
--- kern/kern_descrip.c 19 Jan 2015 01:19:17 -  1.116
+++ kern/kern_descrip.c 8 Apr 2015 09:21:19 -
@@ -61,6 +61,7 @@
 #include sys/event.h
 #include sys/pool.h
 #include sys/ktrace.h
+#include sys/atomic.h
 
 #include sys/pipe.h
 
@@ -332,6 +333,7 @@ sys_fcntl(struct proc *p, void *v, regis
int i, tmp, newmin, flg = F_POSIX;
struct flock fl;
int error = 0;
+   int oflag, nflag;
 
 restart:
if ((fp = fd_getfile(fdp, fd)) == NULL)
@@ -384,8 +386,12 @@ restart:
break;
 
case F_SETFL:
-   fp-f_flag = ~FCNTLFLAGS;
-   fp-f_flag |= FFLAGS((long)SCARG(uap, arg))  FCNTLFLAGS;
+   do {
+   oflag = fp-f_flag;
+   nflag = oflag  ~FCNTLFLAGS;
+   nflag |= FFLAGS((long)SCARG(uap, arg))  FCNTLFLAGS;
+   } while (atomic_cas_uint(fp-f_flag, oflag, nflag) != oflag);
+
tmp = fp-f_flag  FNONBLOCK;
error = (*fp-f_ops-fo_ioctl)(fp, FIONBIO, (caddr_t)tmp, p);
if (error)
@@ -394,7 +400,7 @@ restart:
error = (*fp-f_ops-fo_ioctl)(fp, FIOASYNC, (caddr_t)tmp, p);
if (!error)
break;
-   fp-f_flag = ~FNONBLOCK;
+   atomic_clearbits_int(fp-f_flag, FNONBLOCK);
tmp = 0;
(void) (*fp-f_ops-fo_ioctl)(fp, FIONBIO, (caddr_t)tmp, p);
break;
@@ -1160,7 +1166,7 @@ sys_flock(struct proc *p, void *v, regis
lf.l_len = 0;
if (how  LOCK_UN) {
lf.l_type = F_UNLCK;
-   fp-f_iflags = ~FIF_HASLOCK;
+   atomic_clearbits_int(fp-f_iflags, FIF_HASLOCK);
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, lf, F_FLOCK);
goto out;
}
@@ -1172,7 +1178,7 @@ sys_flock(struct proc *p, void *v, regis
error = EINVAL;
goto out;
}
-   fp-f_iflags |= FIF_HASLOCK;
+   atomic_setbits_int(fp-f_iflags, FIF_HASLOCK);
if (how  LOCK_NB)
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, lf, F_FLOCK);
else
Index: kern/sys_generic.c
===
RCS file: /cvs/src/sys/kern/sys_generic.c,v
retrieving revision 1.96
diff -u -p -r1.96 sys_generic.c
--- kern/sys_generic.c  12 Feb 2015 22:27:04 -  1.96
+++ kern/sys_generic.c  8 Apr 2015 09:21:19 -
@@ -52,6 +52,7 @@
 #include sys/stat.h
 #include sys/malloc.h
 #include sys/poll.h
+#include sys/atomic.h
 #ifdef KTRACE
 #include sys/ktrace.h
 #endif
@@ -456,17 +457,17 @@ sys_ioctl(struct proc *p, void *v, regis
 
case FIONBIO:
if ((tmp = *(int *)data) != 0)
-   fp-f_flag |= FNONBLOCK;
+   atomic_setbits_int(fp-f_flag, FNONBLOCK);
else
-   fp-f_flag = ~FNONBLOCK;
+   atomic_clearbits_int(fp-f_flag, FNONBLOCK);
error = (*fp-f_ops-fo_ioctl)(fp, FIONBIO, (caddr_t)tmp, p);
break;
 
case FIOASYNC:
if ((tmp = *(int *)data) != 0)
-   fp-f_flag |= FASYNC;
+   atomic_setbits_int(fp-f_flag, FASYNC);
else
-   fp-f_flag = ~FASYNC;
+   atomic_clearbits_int(fp-f_flag, FASYNC);
error = (*fp-f_ops-fo_ioctl)(fp, FIOASYNC, (caddr_t)tmp, p);
break;
 
Index: kern/uipc_usrreq.c
===
RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.79
diff -u -p -r1.79 uipc_usrreq.c
--- kern/uipc_usrreq.c  11 Dec 2014 19:21:57 -  1.79
+++ kern/uipc_usrreq.c  8 Apr 2015 09:21:19 -
@@ -884,11 +884,11 @@ unp_gc(void)
unp_gcing = 1;
unp_defer = 0;
 

Re: falloc and related stuff

2015-04-08 Thread Ted Unangst
kanonenvogel@gmail.com wrote:
 
 On 08 Apr 2015, at 02:31, Philip Guenther guent...@gmail.com wrote:
 
  On Tue, Apr 7, 2015 at 3:57 PM, Kanonenvogel kanonenvogel@gmail.com 
  wrote:
  I have idea to modify falloc() function and related logic.
  Now, after successful faclloc call,  we have half-initialized struct file 
  object, protected by FIF_LARVAL flag.
  I want to initialise struct file object within falloc() and then put it to 
  fd_ofiles array and filehead list. This modification
  permits to avoid half-initialization state and remove FIF_LARVAL flag and 
  related logic.
  
  The hard case is blocking opens of fifos, as the underlying operation
  involves a change visible to another process and that therefore cannot
  be rolled back.
  
  
  Philip Guenther
 Ok, I understood.
 And what about make struct file more smp friendly? For example, make 
 operations under
 f_iflags and f_flags atomic?

This can help, but not always. The atomic functions are quite expensive on
some architectures, so we don't want to just use them everywhere.

Also, this only helps if you're sure that the code reading the flag will do so
in an smp safe way. In many cases, the reading code will also need to acquire
a lock in order to correctly do something after reading the flag. From the
diff context, it looks like most of this code will definitely already have
some other lock.



Re: falloc and related stuff

2015-04-08 Thread kanonenvogel . 87g

On 08 Apr 2015, at 17:33, kanonenvogel@gmail.com wrote:
 
 Is it a good idea?

bad idea because of sys_pread



Re: falloc and related stuff

2015-04-08 Thread kanonenvogel....@gmail.com

On 08 Apr 2015, at 17:33, kanonenvogel@gmail.com wrote:
 
 Is it a good idea?

bad idea because of sys_pread/sys_pwrite



Re: falloc and related stuff

2015-04-08 Thread kanonenvogel....@gmail.com

On 08 Apr 2015, at 15:03, Ted Unangst t...@tedunangst.com wrote:

 The atomic functions are quite expensive on
 some architectures, so we don't want to just use them everywhere.
So, rwlock is better here?

Also, can you explain this lines from finishdup() function (openbsd-5., file 
kern/kern_descrip.c, lines 576-577):
fp-f_count++;
FRELE(fp, p);

it looks useless, or I misunderstood something?




Re: falloc and related stuff

2015-04-08 Thread kanonenvogel....@gmail.com

On 08 Apr 2015, at 15:03, Ted Unangst t...@tedunangst.com wrote:
 Also, this only helps if you're sure that the code reading the flag will do so
 in an smp safe way. In many cases, the reading code will also need to acquire
 a lock in order to correctly do something after reading the flag. From the
 diff context, it looks like most of this code will definitely already have
 some other lock.
What do you think about f_offset protection? Lock file struct object within 
of_read or fo_write routine?
For example for vn_read()

int
vn_read(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
{
struct vnode *vp = (struct vnode *)fp-f_data;
int error = 0;
size_t count = uio-uio_resid;
struct proc *p = uio-uio_procp;

FILE_LOCK(fp);
/* no wrap around of offsets except on character devices */
if (vp-v_type != VCHR  count  LLONG_MAX - *poff) {
FILE_UNLOCK(fp);
return (EINVAL);
}
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
uio-uio_offset = *poff;
if (vp-v_type != VDIR)
error = VOP_READ(vp, uio,
(fp-f_flag  FNONBLOCK) ? IO_NDELAY : 0, cred);
*poff += count - uio-uio_resid;
VOP_UNLOCK(vp, 0, p);
FILE_UNLOCK(fp);
return (error);
}

Is it a good idea?





Re: falloc and related stuff

2015-04-07 Thread Philip Guenther
On Tue, Apr 7, 2015 at 3:57 PM, Kanonenvogel kanonenvogel@gmail.com wrote:
 I have idea to modify falloc() function and related logic.
 Now, after successful faclloc call,  we have half-initialized struct file 
 object, protected by FIF_LARVAL flag.
 I want to initialise struct file object within falloc() and then put it to 
 fd_ofiles array and filehead list. This modification
 permits to avoid half-initialization state and remove FIF_LARVAL flag and 
 related logic.

The hard case is blocking opens of fifos, as the underlying operation
involves a change visible to another process and that therefore cannot
be rolled back.


Philip Guenther



falloc and related stuff

2015-04-07 Thread Kanonenvogel
Hello.
I have idea to modify falloc() function and related logic.
Now, after successful faclloc call,  we have half-initialized struct file 
object, protected by FIF_LARVAL flag.
I want to initialise struct file object within falloc() and then put it to 
fd_ofiles array and filehead list. This modification
permits to avoid half-initialization state and remove FIF_LARVAL flag and 
related logic.
After, I want to protect struct file by rwlock, add something like SY_NOLOCK 
flag and logic and begin
to move related syscalls from KERNEL_LOCK. What do you think about?